From 200778af263d6a12c749bb7917d44bb5cb86bfe1 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Fri, 19 Jun 2026 08:50:59 -0700 Subject: [PATCH] Fix max range, range cursor, and stc range control readouts --- CLAUDE.md | 8 +- current_build_instructions | 35 +++++++- global_data.cpp | 13 ++- include/02_text_description.h | 8 ++ include/data_structure_and_constants.h | 11 ++- include/settings.h | 55 ++++++++++-- src/01_classes.cpp | 72 ++++++++++------ src/02_text_description.cpp | 32 +++++++ src/main.cpp | 115 ++++++++++++++++++++++--- 9 files changed, 286 insertions(+), 63 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a68e831..a83f783 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -227,9 +227,11 @@ These are knobs on the panel once that is built. Keyboard keys until then i for right turn. - uniform is float radiogoniometer; 8. Maximum Range for all scopes except for chain home, which is fixed. This control will not operate for Chain Home. These maximum - range selections will be defined for each scope; If you try to go beyond the stated - maximum ranges, the control will have no effect; note that the default maximum range would - be the highest for that scope; keyboard o for lower; p for higher uniform is float max_range; + This is a stop control. Each step for for each maximum range for the selected radar. + those maximum ranges are in a table in settings.h. If you try to step beyond the top maximum + range for that radar, the step higher will do noting. If yoi try to step beyond the lowest + maximum range, the the lower step key will be ignored. + keyboard o for stepping lower; p for stepping higher. uniform is float max_range; 9. Range Cursor (for ppi scopes, not for a scopes) keyboard a for lower; s for higher - uniform is float range_cursor; 10. Bearing Cursor (for all ppi scopes; not for a scopes) diff --git a/current_build_instructions b/current_build_instructions index 8d3e8fb..45917d0 100644 --- a/current_build_instructions +++ b/current_build_instructions @@ -1,4 +1,33 @@ -1. build a stub for each radar that displays it's information in the left panel; then show the settngs of its controls on the status panel. In the main scope, just put the name in that panel. We do not have -any workings. This is only for testing the operation of the initialization and management. +As you know, you have enabled the controls on each radar enough to show that they are working, although +there are no uniform variables yet in the shaders. -2. Set the radar management structure to have all radars fully built and available to enable the operator to go through the radar selection and operating the controls. +This next step is to correct a mistake I made, especially with the maximum range settings for the radars +as well as the cursors. + +First of all remove the control for the maximum range for the chain home radar. The only range option +for that is 200 nm. This means removing the control as well as setting the global variable for the +maximum range for chain home to 200nm. Later on when development starts with chain home, we need to +have a uniform variable for maximum range. + +Here are the changes I need for the controls. + +Impliment the step changes for the maximum range and indicate the maximum range in the text +status. I changed the maximum range setting to the step setting. + +The control for the bearing shouid show the following: + +1. Degrees from true north, going clockwise for advance or counterclockwise for keyboard for going + down. This is for chain home, ascope marine, and marine traffic control. + +2. Degrees from front of boat for the police boat radar, going clockwise for advance or + counterclockwise for keyboard for going + +3. Note that clockwise is the direction for bearing going positive. + +4. If the operator goes beyond the meximum of 360 clockwise, we reset to 0 + and if the operator goes below 0 counterclockwise, we reset to 360. + + +The control for the range cursor; keep normalized from 0 to 1. However, please take that +normalized value and convert to actual range using the current max range setting and display +the actual range in the text status window. diff --git a/global_data.cpp b/global_data.cpp index 89a2be4..f02e2e6 100644 --- a/global_data.cpp +++ b/global_data.cpp @@ -122,10 +122,15 @@ float uniform_noise_filter = 0.0f; // Components: Chain Home A-scope float uniform_radiogoniometer = 0.0f; -// Maximum radar range (scope-dependent units) — keyboard o (lower) / p (higher) -// GLSL uniform: float max_range -// Components: Marine A-scope, PPI scopes (not Chain Home; that is fixed) -float uniform_max_range = 1.0f; +/* + * Maximum radar range in nautical miles (NOT normalized). + * Chain Home: fixed at CHAIN_HOME_MAX_RANGE_NM; o/p keys ignored. + * Others: set from the radar's step table when a radar is activated; updated by o/p. + * 0.0 is the placeholder before any radar is selected. + * GLSL uniform: float max_range + * Components: all scope renderers + */ +float uniform_max_range = 0.0f; // Range cursor position (normalized 0-1) — keyboard a (lower) / s (higher) // GLSL uniform: float range_cursor diff --git a/include/02_text_description.h b/include/02_text_description.h index 1747a63..d856d39 100644 --- a/include/02_text_description.h +++ b/include/02_text_description.h @@ -78,6 +78,14 @@ public: /* Return the rendered pixel width of text at the given scale. */ float get_text_width(const std::string& text, float scale) const; + /* Render text at (x, y), wrapping on word boundaries when a line would + * exceed max_width pixels. y is decremented by line_height * scale after + * each rendered line, including the last. Never breaks within a word. */ + void render_text_wrapped(const std::string& text, + float x, float& y, float scale, + float max_width, float line_height, + float color_r, float color_g, float color_b); + /* Set the orthographic projection for a viewport of w × h pixels. * Call this each time glViewport changes before rendering text. */ void set_projection(int w, int h); diff --git a/include/data_structure_and_constants.h b/include/data_structure_and_constants.h index 1451769..349af4c 100644 --- a/include/data_structure_and_constants.h +++ b/include/data_structure_and_constants.h @@ -194,9 +194,14 @@ extern float uniform_noise_filter; // Components: Chain Home A-scope extern float uniform_radiogoniometer; -// Maximum radar range, all scopes except Chain Home — keyboard o (lower) / p (higher) -// GLSL uniform: float max_range -// Components: Marine A-scope, PPI scopes +/* + * Maximum radar range in nautical miles (NOT normalized). + * Chain Home is fixed at CHAIN_HOME_MAX_RANGE_NM; the o/p keys have no effect for it. + * For other radars the value is taken from the radar's step table and updated by o/p. + * Set via reset_radar_controls() when a radar is activated. + * GLSL uniform: float max_range + * Components: all scope renderers + */ extern float uniform_max_range; // Range cursor, PPI scopes only — keyboard a (lower) / s (higher) diff --git a/include/settings.h b/include/settings.h index d61cec5..23fa727 100644 --- a/include/settings.h +++ b/include/settings.h @@ -86,47 +86,85 @@ * Component: Chain Home scope (1940s, World War 2) * ============================================================ */ -// Fixed maximum range in km; the max_range control has no effect for this scope -#define CHAIN_HOME_MAX_RANGE_KM 200.0f +// Fixed maximum range in nautical miles; the o/p range control has no effect for this scope +#define CHAIN_HOME_MAX_RANGE_NM 200.0f /* ============================================================ * MARINE A-SCOPE * Component: 1940s marine A-scope (pre-PPI) * ============================================================ */ -// Selectable maximum range steps in nautical miles (o/p keys cycle through these) -#define MARINE_A_SCOPE_NUM_RANGES 4 +// Selectable maximum range steps in nautical miles (o/p keys step through these) +#define MARINE_A_SCOPE_NUM_RANGES 4 #define MARINE_A_SCOPE_RANGE_STEP_1 3.0f #define MARINE_A_SCOPE_RANGE_STEP_2 6.0f #define MARINE_A_SCOPE_RANGE_STEP_3 12.0f #define MARINE_A_SCOPE_RANGE_STEP_4 24.0f +// Pip spacing on the A-scope sweep (nm between range pips), one value per range step +#define MARINE_A_SCOPE_PIP_STEP_1 0.5f /* 3 nm range — pip every 0.5 nm */ +#define MARINE_A_SCOPE_PIP_STEP_2 1.0f /* 6 nm range — pip every 1.0 nm */ +#define MARINE_A_SCOPE_PIP_STEP_3 2.0f /* 12 nm range — pip every 2.0 nm */ +#define MARINE_A_SCOPE_PIP_STEP_4 4.0f /* 24 nm range — pip every 4.0 nm */ + /* ============================================================ * PPI SCOPE - MARINE TRAFFIC CONTROL * Component: PPI scope, marine traffic control station * ============================================================ */ // Selectable maximum range steps in nautical miles -#define PPI_MTC_NUM_RANGES 5 +#define PPI_MTC_NUM_RANGES 5 #define PPI_MTC_RANGE_STEP_1 3.0f #define PPI_MTC_RANGE_STEP_2 6.0f #define PPI_MTC_RANGE_STEP_3 12.0f #define PPI_MTC_RANGE_STEP_4 24.0f #define PPI_MTC_RANGE_STEP_5 48.0f +/* + * Range ring positions (nm from centre) per range step. + * Two rings per step, placed at 1/3 and 2/3 of the maximum range. + * No ring at the maximum range itself — that is the scope edge / graticule boundary. + */ +#define PPI_MTC_RING1_STEP_1 1.0f /* 3 nm — inner ring */ +#define PPI_MTC_RING2_STEP_1 2.0f /* 3 nm — outer ring */ +#define PPI_MTC_RING1_STEP_2 2.0f /* 6 nm */ +#define PPI_MTC_RING2_STEP_2 4.0f +#define PPI_MTC_RING1_STEP_3 4.0f /* 12 nm */ +#define PPI_MTC_RING2_STEP_3 8.0f +#define PPI_MTC_RING1_STEP_4 8.0f /* 24 nm */ +#define PPI_MTC_RING2_STEP_4 16.0f +#define PPI_MTC_RING1_STEP_5 16.0f /* 48 nm */ +#define PPI_MTC_RING2_STEP_5 32.0f + /* ============================================================ * PPI SCOPE - ON-BOARD BOAT * Component: PPI scope, on-board boat view * ============================================================ */ // Selectable maximum range steps in nautical miles -#define PPI_BOAT_NUM_RANGES 5 +#define PPI_BOAT_NUM_RANGES 5 #define PPI_BOAT_RANGE_STEP_1 1.5f #define PPI_BOAT_RANGE_STEP_2 3.0f #define PPI_BOAT_RANGE_STEP_3 6.0f #define PPI_BOAT_RANGE_STEP_4 12.0f #define PPI_BOAT_RANGE_STEP_5 24.0f +/* + * Range ring positions (nm from centre) per range step. + * Two rings per step, placed at 1/3 and 2/3 of the maximum range. + * No ring at the maximum range itself — that is the scope edge / graticule boundary. + */ +#define PPI_BOAT_RING1_STEP_1 0.5f /* 1.5 nm — inner ring */ +#define PPI_BOAT_RING2_STEP_1 1.0f /* 1.5 nm — outer ring */ +#define PPI_BOAT_RING1_STEP_2 1.0f /* 3 nm */ +#define PPI_BOAT_RING2_STEP_2 2.0f +#define PPI_BOAT_RING1_STEP_3 2.0f /* 6 nm */ +#define PPI_BOAT_RING2_STEP_3 4.0f +#define PPI_BOAT_RING1_STEP_4 4.0f /* 12 nm */ +#define PPI_BOAT_RING2_STEP_4 8.0f +#define PPI_BOAT_RING1_STEP_5 8.0f /* 24 nm */ +#define PPI_BOAT_RING2_STEP_5 16.0f + /* ============================================================ * WINDOW AND PANEL LAYOUT * Component: Thread 1 (main.cpp), 01_classes, 02_text_description @@ -198,7 +236,7 @@ #define BEARING_CURSOR_STEP 1.0f #define RANGE_CURSOR_STEP 0.02f #define MARINE_A_BEARING_STEP 1.0f -#define MAX_RANGE_STEP 0.1f +// Max range is now step-indexed (see MARINE_A_SCOPE_*, PPI_MTC_*, PPI_BOAT_* tables above) /* ============================================================ * KEYBOARD CONTROL LIMITS @@ -217,5 +255,4 @@ #define NOISE_FILTER_MAX 1.0f #define RANGE_CURSOR_MIN 0.0f #define RANGE_CURSOR_MAX 1.0f -#define MAX_RANGE_MIN 0.1f -#define MAX_RANGE_MAX 1.0f +// Max range limits removed — range is now step-indexed, clamped by table size diff --git a/src/01_classes.cpp b/src/01_classes.cpp index ac43062..5bbe0ca 100644 --- a/src/01_classes.cpp +++ b/src/01_classes.cpp @@ -80,6 +80,14 @@ static void text_line(const std::string& text, float x, float& y, y -= LH * scale; } +/* Render a body-text line with word wrapping; y advances by one line per + * wrapped output line. max_width is the available horizontal pixel span. */ +static void text_line_wrapped(const std::string& text, float x, float& y, + float scale, float max_width, + float cr, float cg, float cb) { + g_text_renderer.render_text_wrapped(text, x, y, scale, max_width, LH, cr, cg, cb); +} + /* Render one title-size line using the large renderer at scale 1.0. */ static void text_line_large(const std::string& text, float x, float& y, float cr, float cg, float cb) { @@ -151,12 +159,12 @@ static void render_scope_name(const std::string& radar_name) { static void render_common_status(float x, float& y, float scale) { char buf[320]; snprintf(buf, sizeof(buf), - "Intensity: %.2f | Sensitivity: %.2f | STC Sens: %.2f | STC Range: %.2f", + "Intensity: %.2f | Sensitivity: %.2f | STC Sens: %.2f | STC Range: %.1f nm", uniform_intensity, uniform_sensitivity, - uniform_stc_sensitivity, uniform_stc_range); - g_text_renderer.render_text(buf, x, y, scale, - COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); - y -= LH * scale; + uniform_stc_sensitivity, uniform_stc_range * uniform_max_range); + float max_w = static_cast(LEFT_PANEL_WIDTH) - 2.0f * MARGIN; + text_line_wrapped(buf, x, y, scale, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); } /* ================================================================== */ @@ -221,16 +229,18 @@ void ChainHomeRadar::render_scope() { void ChainHomeRadar::render_status_bar() { float x = MARGIN; float y = static_cast(STATUS_BAR_HEIGHT) - MARGIN - LH; + float max_w = static_cast(LEFT_PANEL_WIDTH) - 2.0f * MARGIN; - text_line("CHAIN HOME RADAR (Ventnor, Isle of Wight) | Fixed range: 200 km", - x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped("CHAIN HOME RADAR (Ventnor, Isle of Wight) | Fixed range: 200 nm", + x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); render_common_status(x, y, SCALE_NORMAL); char buf[200]; snprintf(buf, sizeof(buf), "Radiogoniometer: %.1f deg", uniform_radiogoniometer); - g_text_renderer.render_text(buf, x, y, SCALE_NORMAL, - COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); } /* ================================================================== */ @@ -291,18 +301,20 @@ void MarineAScopeRadar::render_scope() { void MarineAScopeRadar::render_status_bar() { float x = MARGIN; float y = static_cast(STATUS_BAR_HEIGHT) - MARGIN - LH; + float max_w = static_cast(LEFT_PANEL_WIDTH) - 2.0f * MARGIN; - text_line("MARINE A-SCOPE RADAR (Community Boating Center, Bellingham Bay)", - x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped("MARINE A-SCOPE RADAR (Community Boating Center, Bellingham Bay)", + x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); render_common_status(x, y, SCALE_NORMAL); char buf[200]; snprintf(buf, sizeof(buf), - "Max Range (normalized): %.2f | Antenna Bearing: %.1f deg", + "Max Range: %.1f nm | Antenna Bearing: %.1f deg", uniform_max_range, uniform_marine_a_bearing); - g_text_renderer.render_text(buf, x, y, SCALE_NORMAL, - COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); } /* ================================================================== */ @@ -365,20 +377,22 @@ void MarineTrafficRadar::render_scope() { void MarineTrafficRadar::render_status_bar() { float x = MARGIN; float y = static_cast(STATUS_BAR_HEIGHT) - MARGIN - LH; + float max_w = static_cast(LEFT_PANEL_WIDTH) - 2.0f * MARGIN; - text_line("MARINE TRAFFIC CONTROL RADAR (Bellingham Bay)", - x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped("MARINE TRAFFIC CONTROL RADAR (Bellingham Bay)", + x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); render_common_status(x, y, SCALE_NORMAL); char buf[280]; snprintf(buf, sizeof(buf), - "Noise Filter: %.2f | Max Range (norm): %.2f | " - "Range Cursor: %.2f | Bearing Cursor: %.1f deg", + "Noise Filter: %.2f | Max Range: %.1f nm | " + "Range Cursor: %.2f nm | Bearing Cursor: %.1f deg", uniform_noise_filter, uniform_max_range, - uniform_range_cursor, uniform_bearing_cursor); - g_text_renderer.render_text(buf, x, y, SCALE_NORMAL, - COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + uniform_range_cursor * uniform_max_range, uniform_bearing_cursor); + text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); } /* ================================================================== */ @@ -443,18 +457,20 @@ void PoliceboatRadar::render_scope() { void PoliceboatRadar::render_status_bar() { float x = MARGIN; float y = static_cast(STATUS_BAR_HEIGHT) - MARGIN - LH; + float max_w = static_cast(LEFT_PANEL_WIDTH) - 2.0f * MARGIN; - text_line("POLICE BOAT RADAR (Bellingham Bay - moving)", - x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + text_line_wrapped("POLICE BOAT RADAR (Bellingham Bay - moving)", + x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); render_common_status(x, y, SCALE_NORMAL); char buf[280]; snprintf(buf, sizeof(buf), - "Noise Filter: %.2f | Max Range (norm): %.2f | " - "Range Cursor: %.2f | Bearing Cursor: %.1f deg", + "Noise Filter: %.2f | Max Range: %.1f nm | " + "Range Cursor: %.2f nm | Bearing Cursor: %.1f deg", uniform_noise_filter, uniform_max_range, - uniform_range_cursor, uniform_bearing_cursor); - g_text_renderer.render_text(buf, x, y, SCALE_NORMAL, - COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); + uniform_range_cursor * uniform_max_range, uniform_bearing_cursor); + text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w, + COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]); } diff --git a/src/02_text_description.cpp b/src/02_text_description.cpp index f8b468f..0b2040f 100644 --- a/src/02_text_description.cpp +++ b/src/02_text_description.cpp @@ -247,6 +247,38 @@ float TextRenderer::get_text_width(const std::string& text, float scale) const { return width; } +void TextRenderer::render_text_wrapped(const std::string& text, + float x, float& y, float scale, + float max_width, float line_height, + float color_r, float color_g, float color_b) { + std::string line; + std::string::size_type pos = 0; + std::string::size_type slen = text.length(); + + while (pos <= slen) { + std::string::size_type nxt = text.find(' ', pos); + if (nxt == std::string::npos) nxt = slen; + + std::string word = text.substr(pos, nxt - pos); + if (!word.empty()) { + std::string candidate = line.empty() ? word : (line + " " + word); + if (!line.empty() && get_text_width(candidate, scale) > max_width) { + render_text(line, x, y, scale, color_r, color_g, color_b); + y -= line_height * scale; + line = word; + } else { + line = candidate; + } + } + pos = nxt + 1; + } + + if (!line.empty()) { + render_text(line, x, y, scale, color_r, color_g, color_b); + y -= line_height * scale; + } +} + void TextRenderer::set_projection(int w, int h) { /* Column-major orthographic matrix mapping pixel space [0,w]x[0,h] * to NDC. Near=-1, far=1 (depth unused for 2D text). */ diff --git a/src/main.cpp b/src/main.cpp index 65c69ba..f5a43db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,6 +57,27 @@ #include #include +/* ------------------------------------------------------------------ */ +/* Range step lookup tables */ +/* Mirror the settings.h defines as arrays so the keyboard handler */ +/* can index them at run time. */ +/* ------------------------------------------------------------------ */ + +static const float ASCOPE_RANGES[MARINE_A_SCOPE_NUM_RANGES] = { + MARINE_A_SCOPE_RANGE_STEP_1, MARINE_A_SCOPE_RANGE_STEP_2, + MARINE_A_SCOPE_RANGE_STEP_3, MARINE_A_SCOPE_RANGE_STEP_4 +}; + +static const float MTC_RANGES[PPI_MTC_NUM_RANGES] = { + PPI_MTC_RANGE_STEP_1, PPI_MTC_RANGE_STEP_2, PPI_MTC_RANGE_STEP_3, + PPI_MTC_RANGE_STEP_4, PPI_MTC_RANGE_STEP_5 +}; + +static const float BOAT_RANGES[PPI_BOAT_NUM_RANGES] = { + PPI_BOAT_RANGE_STEP_1, PPI_BOAT_RANGE_STEP_2, PPI_BOAT_RANGE_STEP_3, + PPI_BOAT_RANGE_STEP_4, PPI_BOAT_RANGE_STEP_5 +}; + /* ------------------------------------------------------------------ */ /* Debug border-box line renderer (DEBUG_DRAW_WINDOW_BORDERS) */ /* ------------------------------------------------------------------ */ @@ -242,6 +263,36 @@ static void GLAPIENTRY gl_debug_callback(GLenum /*source*/, fprintf(stderr, "[GL %s] %s\n", type_str, message); } +/* ------------------------------------------------------------------ */ +/* reset_radar_controls: called when a radar is activated */ +/* Resets range to the widest step and zeroes the cursors. */ +/* ------------------------------------------------------------------ */ + +static void reset_radar_controls(int radar_idx) { + switch (radar_idx) { + case RADAR_CHAIN_HOME: + uniform_max_range = CHAIN_HOME_MAX_RANGE_NM; + break; + case RADAR_MARINE_ASCOPE: + ascope_range_setting = MARINE_A_SCOPE_NUM_RANGES - 1; + uniform_max_range = ASCOPE_RANGES[ascope_range_setting]; + break; + case RADAR_MARINE_TRAFFIC: + traffic_control_range_setting = PPI_MTC_NUM_RANGES - 1; + uniform_max_range = MTC_RANGES[traffic_control_range_setting]; + break; + case RADAR_POLICE_BOAT: + police_boat_range_setting = PPI_BOAT_NUM_RANGES - 1; + uniform_max_range = BOAT_RANGES[police_boat_range_setting]; + break; + default: + uniform_max_range = 0.0f; + break; + } + uniform_range_cursor = 0.0f; + uniform_bearing_cursor = 0.0f; +} + /* ------------------------------------------------------------------ */ /* Keyboard callback (Thread 1) */ /* ------------------------------------------------------------------ */ @@ -267,13 +318,14 @@ static void key_callback(GLFWwindow* window, int key, int /*scancode*/, (g_selection_cursor - 1 + static_cast(g_selectable.size())) % static_cast(g_selectable.size()); } else if (key == GLFW_KEY_ENTER || key == GLFW_KEY_KP_ENTER) { - /* Activate selected radar. */ + /* Activate selected radar; reset all controls to defaults for that radar. */ int mi = g_selectable[g_selection_cursor].management_index; for (int i = 0; i < RADAR_COUNT; i++) radar_management[i].selected = 0; radar_management[mi].selected = 1; current_radar = mi; g_active_radar = g_selectable[g_selection_cursor].instance; g_app_state = AppState::OPERATING; + reset_radar_controls(mi); } return; } @@ -363,17 +415,43 @@ static void key_callback(GLFWwindow* window, int key, int /*scancode*/, } break; - /* Max range (all scopes except Chain Home) */ + /* Max range — step lower (shorter range / zoom in); Chain Home: no effect */ case GLFW_KEY_O: - if (current_radar != RADAR_CHAIN_HOME) { - uniform_max_range = std::max(MAX_RANGE_MIN, - uniform_max_range - MAX_RANGE_STEP); + if (current_radar == RADAR_MARINE_ASCOPE) { + if (ascope_range_setting > 0) { + ascope_range_setting--; + uniform_max_range = ASCOPE_RANGES[ascope_range_setting]; + } + } else if (current_radar == RADAR_MARINE_TRAFFIC) { + if (traffic_control_range_setting > 0) { + traffic_control_range_setting--; + uniform_max_range = MTC_RANGES[traffic_control_range_setting]; + } + } else if (current_radar == RADAR_POLICE_BOAT) { + if (police_boat_range_setting > 0) { + police_boat_range_setting--; + uniform_max_range = BOAT_RANGES[police_boat_range_setting]; + } } break; + + /* Max range — step higher (longer range / zoom out); Chain Home: no effect */ case GLFW_KEY_P: - if (current_radar != RADAR_CHAIN_HOME) { - uniform_max_range = std::min(MAX_RANGE_MAX, - uniform_max_range + MAX_RANGE_STEP); + if (current_radar == RADAR_MARINE_ASCOPE) { + if (ascope_range_setting < MARINE_A_SCOPE_NUM_RANGES - 1) { + ascope_range_setting++; + uniform_max_range = ASCOPE_RANGES[ascope_range_setting]; + } + } else if (current_radar == RADAR_MARINE_TRAFFIC) { + if (traffic_control_range_setting < PPI_MTC_NUM_RANGES - 1) { + traffic_control_range_setting++; + uniform_max_range = MTC_RANGES[traffic_control_range_setting]; + } + } else if (current_radar == RADAR_POLICE_BOAT) { + if (police_boat_range_setting < PPI_BOAT_NUM_RANGES - 1) { + police_boat_range_setting++; + uniform_max_range = BOAT_RANGES[police_boat_range_setting]; + } } break; @@ -578,26 +656,33 @@ static void render_radar_list() { static void render_selection_status_bar() { float x = MARGIN; float y = static_cast(STATUS_BAR_HEIGHT) - MARGIN - LH_MAIN; + float xp; + /* Line 1: "Use 1 / 2 to change selection." */ g_text_renderer.render_text("Use ", x, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); - float xp = x + g_text_renderer.get_text_width("Use ", 1.0f); + xp = x + g_text_renderer.get_text_width("Use ", 1.0f); g_text_renderer.render_text("1", xp, y, 1.0f, COL_PINK[0], COL_PINK[1], COL_PINK[2]); xp += g_text_renderer.get_text_width("1", 1.0f); - g_text_renderer.render_text(" / ", xp, y, 1.0f, + g_text_renderer.render_text(" / ", xp, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); - xp += g_text_renderer.get_text_width(" / ", 1.0f); + xp += g_text_renderer.get_text_width(" / ", 1.0f); g_text_renderer.render_text("2", xp, y, 1.0f, COL_PINK[0], COL_PINK[1], COL_PINK[2]); xp += g_text_renderer.get_text_width("2", 1.0f); - g_text_renderer.render_text(" to move the selection. Press ", xp, y, 1.0f, + g_text_renderer.render_text(" to change selection.", xp, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); - xp += g_text_renderer.get_text_width(" to move the selection. Press ", 1.0f); + + /* Line 2: "Press ENTER to activate." */ + y -= LH_MAIN; + g_text_renderer.render_text("Press ", x, y, 1.0f, + COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); + xp = x + g_text_renderer.get_text_width("Press ", 1.0f); g_text_renderer.render_text("ENTER", xp, y, 1.0f, COL_PINK[0], COL_PINK[1], COL_PINK[2]); @@ -606,13 +691,16 @@ static void render_selection_status_bar() { g_text_renderer.render_text(" to activate.", xp, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); + /* Line 3: "Press ESC to exit the exhibit." */ y -= LH_MAIN; g_text_renderer.render_text("Press ", x, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); xp = x + g_text_renderer.get_text_width("Press ", 1.0f); + g_text_renderer.render_text("ESC", xp, y, 1.0f, COL_PINK[0], COL_PINK[1], COL_PINK[2]); xp += g_text_renderer.get_text_width("ESC", 1.0f); + g_text_renderer.render_text(" to exit the exhibit.", xp, y, 1.0f, COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]); } @@ -827,6 +915,7 @@ int main(int argc, char* argv[]) { current_radar = g_selectable[0].management_index; g_active_radar = g_selectable[0].instance; g_app_state = AppState::OPERATING; + reset_radar_controls(current_radar); } }