Fix max range, range cursor, and stc range control readouts
This commit is contained in:
@@ -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;
|
i for right turn. - uniform is float radiogoniometer;
|
||||||
8. Maximum Range for all scopes except for chain home, which is fixed. This control
|
8. Maximum Range for all scopes except for chain home, which is fixed. This control
|
||||||
will not operate for Chain Home. These maximum
|
will not operate for Chain Home. These maximum
|
||||||
range selections will be defined for each scope; If you try to go beyond the stated
|
This is a stop control. Each step for for each maximum range for the selected radar.
|
||||||
maximum ranges, the control will have no effect; note that the default maximum range would
|
those maximum ranges are in a table in settings.h. If you try to step beyond the top maximum
|
||||||
be the highest for that scope; keyboard o for lower; p for higher uniform is float max_range;
|
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)
|
9. Range Cursor (for ppi scopes, not for a scopes)
|
||||||
keyboard a for lower; s for higher - uniform is float range_cursor;
|
keyboard a for lower; s for higher - uniform is float range_cursor;
|
||||||
10. Bearing Cursor (for all ppi scopes; not for a scopes)
|
10. Bearing Cursor (for all ppi scopes; not for a scopes)
|
||||||
|
|||||||
@@ -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
|
As you know, you have enabled the controls on each radar enough to show that they are working, although
|
||||||
any workings. This is only for testing the operation of the initialization and management.
|
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.
|
||||||
|
|||||||
@@ -122,10 +122,15 @@ float uniform_noise_filter = 0.0f;
|
|||||||
// Components: Chain Home A-scope
|
// Components: Chain Home A-scope
|
||||||
float uniform_radiogoniometer = 0.0f;
|
float uniform_radiogoniometer = 0.0f;
|
||||||
|
|
||||||
// Maximum radar range (scope-dependent units) — keyboard o (lower) / p (higher)
|
/*
|
||||||
// GLSL uniform: float max_range
|
* Maximum radar range in nautical miles (NOT normalized).
|
||||||
// Components: Marine A-scope, PPI scopes (not Chain Home; that is fixed)
|
* Chain Home: fixed at CHAIN_HOME_MAX_RANGE_NM; o/p keys ignored.
|
||||||
float uniform_max_range = 1.0f;
|
* 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)
|
// Range cursor position (normalized 0-1) — keyboard a (lower) / s (higher)
|
||||||
// GLSL uniform: float range_cursor
|
// GLSL uniform: float range_cursor
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ public:
|
|||||||
/* Return the rendered pixel width of text at the given scale. */
|
/* Return the rendered pixel width of text at the given scale. */
|
||||||
float get_text_width(const std::string& text, float scale) const;
|
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.
|
/* Set the orthographic projection for a viewport of w × h pixels.
|
||||||
* Call this each time glViewport changes before rendering text. */
|
* Call this each time glViewport changes before rendering text. */
|
||||||
void set_projection(int w, int h);
|
void set_projection(int w, int h);
|
||||||
|
|||||||
@@ -194,9 +194,14 @@ extern float uniform_noise_filter;
|
|||||||
// Components: Chain Home A-scope
|
// Components: Chain Home A-scope
|
||||||
extern float uniform_radiogoniometer;
|
extern float uniform_radiogoniometer;
|
||||||
|
|
||||||
// Maximum radar range, all scopes except Chain Home — keyboard o (lower) / p (higher)
|
/*
|
||||||
// GLSL uniform: float max_range
|
* Maximum radar range in nautical miles (NOT normalized).
|
||||||
// Components: Marine A-scope, PPI scopes
|
* 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;
|
extern float uniform_max_range;
|
||||||
|
|
||||||
// Range cursor, PPI scopes only — keyboard a (lower) / s (higher)
|
// Range cursor, PPI scopes only — keyboard a (lower) / s (higher)
|
||||||
|
|||||||
@@ -86,47 +86,85 @@
|
|||||||
* Component: Chain Home scope (1940s, World War 2)
|
* Component: Chain Home scope (1940s, World War 2)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
// Fixed maximum range in km; the max_range control has no effect for this scope
|
// Fixed maximum range in nautical miles; the o/p range control has no effect for this scope
|
||||||
#define CHAIN_HOME_MAX_RANGE_KM 200.0f
|
#define CHAIN_HOME_MAX_RANGE_NM 200.0f
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* MARINE A-SCOPE
|
* MARINE A-SCOPE
|
||||||
* Component: 1940s marine A-scope (pre-PPI)
|
* Component: 1940s marine A-scope (pre-PPI)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
// Selectable maximum range steps in nautical miles (o/p keys cycle through these)
|
// Selectable maximum range steps in nautical miles (o/p keys step through these)
|
||||||
#define MARINE_A_SCOPE_NUM_RANGES 4
|
#define MARINE_A_SCOPE_NUM_RANGES 4
|
||||||
#define MARINE_A_SCOPE_RANGE_STEP_1 3.0f
|
#define MARINE_A_SCOPE_RANGE_STEP_1 3.0f
|
||||||
#define MARINE_A_SCOPE_RANGE_STEP_2 6.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_3 12.0f
|
||||||
#define MARINE_A_SCOPE_RANGE_STEP_4 24.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
|
* PPI SCOPE - MARINE TRAFFIC CONTROL
|
||||||
* Component: PPI scope, marine traffic control station
|
* Component: PPI scope, marine traffic control station
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
// Selectable maximum range steps in nautical miles
|
// 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_1 3.0f
|
||||||
#define PPI_MTC_RANGE_STEP_2 6.0f
|
#define PPI_MTC_RANGE_STEP_2 6.0f
|
||||||
#define PPI_MTC_RANGE_STEP_3 12.0f
|
#define PPI_MTC_RANGE_STEP_3 12.0f
|
||||||
#define PPI_MTC_RANGE_STEP_4 24.0f
|
#define PPI_MTC_RANGE_STEP_4 24.0f
|
||||||
#define PPI_MTC_RANGE_STEP_5 48.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
|
* PPI SCOPE - ON-BOARD BOAT
|
||||||
* Component: PPI scope, on-board boat view
|
* Component: PPI scope, on-board boat view
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
// Selectable maximum range steps in nautical miles
|
// 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_1 1.5f
|
||||||
#define PPI_BOAT_RANGE_STEP_2 3.0f
|
#define PPI_BOAT_RANGE_STEP_2 3.0f
|
||||||
#define PPI_BOAT_RANGE_STEP_3 6.0f
|
#define PPI_BOAT_RANGE_STEP_3 6.0f
|
||||||
#define PPI_BOAT_RANGE_STEP_4 12.0f
|
#define PPI_BOAT_RANGE_STEP_4 12.0f
|
||||||
#define PPI_BOAT_RANGE_STEP_5 24.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
|
* WINDOW AND PANEL LAYOUT
|
||||||
* Component: Thread 1 (main.cpp), 01_classes, 02_text_description
|
* Component: Thread 1 (main.cpp), 01_classes, 02_text_description
|
||||||
@@ -198,7 +236,7 @@
|
|||||||
#define BEARING_CURSOR_STEP 1.0f
|
#define BEARING_CURSOR_STEP 1.0f
|
||||||
#define RANGE_CURSOR_STEP 0.02f
|
#define RANGE_CURSOR_STEP 0.02f
|
||||||
#define MARINE_A_BEARING_STEP 1.0f
|
#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
|
* KEYBOARD CONTROL LIMITS
|
||||||
@@ -217,5 +255,4 @@
|
|||||||
#define NOISE_FILTER_MAX 1.0f
|
#define NOISE_FILTER_MAX 1.0f
|
||||||
#define RANGE_CURSOR_MIN 0.0f
|
#define RANGE_CURSOR_MIN 0.0f
|
||||||
#define RANGE_CURSOR_MAX 1.0f
|
#define RANGE_CURSOR_MAX 1.0f
|
||||||
#define MAX_RANGE_MIN 0.1f
|
// Max range limits removed — range is now step-indexed, clamped by table size
|
||||||
#define MAX_RANGE_MAX 1.0f
|
|
||||||
|
|||||||
@@ -80,6 +80,14 @@ static void text_line(const std::string& text, float x, float& y,
|
|||||||
y -= LH * scale;
|
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. */
|
/* 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,
|
static void text_line_large(const std::string& text, float x, float& y,
|
||||||
float cr, float cg, float cb) {
|
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) {
|
static void render_common_status(float x, float& y, float scale) {
|
||||||
char buf[320];
|
char buf[320];
|
||||||
snprintf(buf, sizeof(buf),
|
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_intensity, uniform_sensitivity,
|
||||||
uniform_stc_sensitivity, uniform_stc_range);
|
uniform_stc_sensitivity, uniform_stc_range * uniform_max_range);
|
||||||
g_text_renderer.render_text(buf, x, y, scale,
|
float max_w = static_cast<float>(LEFT_PANEL_WIDTH) - 2.0f * MARGIN;
|
||||||
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
text_line_wrapped(buf, x, y, scale, max_w,
|
||||||
y -= LH * scale;
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
@@ -221,16 +229,18 @@ void ChainHomeRadar::render_scope() {
|
|||||||
void ChainHomeRadar::render_status_bar() {
|
void ChainHomeRadar::render_status_bar() {
|
||||||
float x = MARGIN;
|
float x = MARGIN;
|
||||||
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
||||||
|
float max_w = static_cast<float>(LEFT_PANEL_WIDTH) - 2.0f * MARGIN;
|
||||||
|
|
||||||
text_line("CHAIN HOME RADAR (Ventnor, Isle of Wight) | Fixed range: 200 km",
|
text_line_wrapped("CHAIN HOME RADAR (Ventnor, Isle of Wight) | Fixed range: 200 nm",
|
||||||
x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
x, y, SCALE_NORMAL, max_w,
|
||||||
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
|
|
||||||
render_common_status(x, y, SCALE_NORMAL);
|
render_common_status(x, y, SCALE_NORMAL);
|
||||||
|
|
||||||
char buf[200];
|
char buf[200];
|
||||||
snprintf(buf, sizeof(buf), "Radiogoniometer: %.1f deg", uniform_radiogoniometer);
|
snprintf(buf, sizeof(buf), "Radiogoniometer: %.1f deg", uniform_radiogoniometer);
|
||||||
g_text_renderer.render_text(buf, x, y, SCALE_NORMAL,
|
text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w,
|
||||||
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
@@ -291,18 +301,20 @@ void MarineAScopeRadar::render_scope() {
|
|||||||
void MarineAScopeRadar::render_status_bar() {
|
void MarineAScopeRadar::render_status_bar() {
|
||||||
float x = MARGIN;
|
float x = MARGIN;
|
||||||
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
||||||
|
float max_w = static_cast<float>(LEFT_PANEL_WIDTH) - 2.0f * MARGIN;
|
||||||
|
|
||||||
text_line("MARINE A-SCOPE RADAR (Community Boating Center, Bellingham Bay)",
|
text_line_wrapped("MARINE A-SCOPE RADAR (Community Boating Center, Bellingham Bay)",
|
||||||
x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
x, y, SCALE_NORMAL, max_w,
|
||||||
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
|
|
||||||
render_common_status(x, y, SCALE_NORMAL);
|
render_common_status(x, y, SCALE_NORMAL);
|
||||||
|
|
||||||
char buf[200];
|
char buf[200];
|
||||||
snprintf(buf, sizeof(buf),
|
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);
|
uniform_max_range, uniform_marine_a_bearing);
|
||||||
g_text_renderer.render_text(buf, x, y, SCALE_NORMAL,
|
text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w,
|
||||||
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
@@ -365,20 +377,22 @@ void MarineTrafficRadar::render_scope() {
|
|||||||
void MarineTrafficRadar::render_status_bar() {
|
void MarineTrafficRadar::render_status_bar() {
|
||||||
float x = MARGIN;
|
float x = MARGIN;
|
||||||
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
||||||
|
float max_w = static_cast<float>(LEFT_PANEL_WIDTH) - 2.0f * MARGIN;
|
||||||
|
|
||||||
text_line("MARINE TRAFFIC CONTROL RADAR (Bellingham Bay)",
|
text_line_wrapped("MARINE TRAFFIC CONTROL RADAR (Bellingham Bay)",
|
||||||
x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
x, y, SCALE_NORMAL, max_w,
|
||||||
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
|
|
||||||
render_common_status(x, y, SCALE_NORMAL);
|
render_common_status(x, y, SCALE_NORMAL);
|
||||||
|
|
||||||
char buf[280];
|
char buf[280];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
"Noise Filter: %.2f | Max Range (norm): %.2f | "
|
"Noise Filter: %.2f | Max Range: %.1f nm | "
|
||||||
"Range Cursor: %.2f | Bearing Cursor: %.1f deg",
|
"Range Cursor: %.2f nm | Bearing Cursor: %.1f deg",
|
||||||
uniform_noise_filter, uniform_max_range,
|
uniform_noise_filter, uniform_max_range,
|
||||||
uniform_range_cursor, uniform_bearing_cursor);
|
uniform_range_cursor * uniform_max_range, uniform_bearing_cursor);
|
||||||
g_text_renderer.render_text(buf, x, y, SCALE_NORMAL,
|
text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w,
|
||||||
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================== */
|
/* ================================================================== */
|
||||||
@@ -443,18 +457,20 @@ void PoliceboatRadar::render_scope() {
|
|||||||
void PoliceboatRadar::render_status_bar() {
|
void PoliceboatRadar::render_status_bar() {
|
||||||
float x = MARGIN;
|
float x = MARGIN;
|
||||||
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH;
|
||||||
|
float max_w = static_cast<float>(LEFT_PANEL_WIDTH) - 2.0f * MARGIN;
|
||||||
|
|
||||||
text_line("POLICE BOAT RADAR (Bellingham Bay - moving)",
|
text_line_wrapped("POLICE BOAT RADAR (Bellingham Bay - moving)",
|
||||||
x, y, SCALE_NORMAL, COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
x, y, SCALE_NORMAL, max_w,
|
||||||
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
|
|
||||||
render_common_status(x, y, SCALE_NORMAL);
|
render_common_status(x, y, SCALE_NORMAL);
|
||||||
|
|
||||||
char buf[280];
|
char buf[280];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
"Noise Filter: %.2f | Max Range (norm): %.2f | "
|
"Noise Filter: %.2f | Max Range: %.1f nm | "
|
||||||
"Range Cursor: %.2f | Bearing Cursor: %.1f deg",
|
"Range Cursor: %.2f nm | Bearing Cursor: %.1f deg",
|
||||||
uniform_noise_filter, uniform_max_range,
|
uniform_noise_filter, uniform_max_range,
|
||||||
uniform_range_cursor, uniform_bearing_cursor);
|
uniform_range_cursor * uniform_max_range, uniform_bearing_cursor);
|
||||||
g_text_renderer.render_text(buf, x, y, SCALE_NORMAL,
|
text_line_wrapped(buf, x, y, SCALE_NORMAL, max_w,
|
||||||
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
COL_YELLOW[0], COL_YELLOW[1], COL_YELLOW[2]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,6 +247,38 @@ float TextRenderer::get_text_width(const std::string& text, float scale) const {
|
|||||||
return width;
|
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) {
|
void TextRenderer::set_projection(int w, int h) {
|
||||||
/* Column-major orthographic matrix mapping pixel space [0,w]x[0,h]
|
/* Column-major orthographic matrix mapping pixel space [0,w]x[0,h]
|
||||||
* to NDC. Near=-1, far=1 (depth unused for 2D text). */
|
* to NDC. Near=-1, far=1 (depth unused for 2D text). */
|
||||||
|
|||||||
115
src/main.cpp
115
src/main.cpp
@@ -57,6 +57,27 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* 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) */
|
/* 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);
|
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) */
|
/* Keyboard callback (Thread 1) */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
@@ -267,13 +318,14 @@ static void key_callback(GLFWwindow* window, int key, int /*scancode*/,
|
|||||||
(g_selection_cursor - 1 + static_cast<int>(g_selectable.size()))
|
(g_selection_cursor - 1 + static_cast<int>(g_selectable.size()))
|
||||||
% static_cast<int>(g_selectable.size());
|
% static_cast<int>(g_selectable.size());
|
||||||
} else if (key == GLFW_KEY_ENTER || key == GLFW_KEY_KP_ENTER) {
|
} 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;
|
int mi = g_selectable[g_selection_cursor].management_index;
|
||||||
for (int i = 0; i < RADAR_COUNT; i++) radar_management[i].selected = 0;
|
for (int i = 0; i < RADAR_COUNT; i++) radar_management[i].selected = 0;
|
||||||
radar_management[mi].selected = 1;
|
radar_management[mi].selected = 1;
|
||||||
current_radar = mi;
|
current_radar = mi;
|
||||||
g_active_radar = g_selectable[g_selection_cursor].instance;
|
g_active_radar = g_selectable[g_selection_cursor].instance;
|
||||||
g_app_state = AppState::OPERATING;
|
g_app_state = AppState::OPERATING;
|
||||||
|
reset_radar_controls(mi);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -363,17 +415,43 @@ static void key_callback(GLFWwindow* window, int key, int /*scancode*/,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Max range (all scopes except Chain Home) */
|
/* Max range — step lower (shorter range / zoom in); Chain Home: no effect */
|
||||||
case GLFW_KEY_O:
|
case GLFW_KEY_O:
|
||||||
if (current_radar != RADAR_CHAIN_HOME) {
|
if (current_radar == RADAR_MARINE_ASCOPE) {
|
||||||
uniform_max_range = std::max(MAX_RANGE_MIN,
|
if (ascope_range_setting > 0) {
|
||||||
uniform_max_range - MAX_RANGE_STEP);
|
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;
|
break;
|
||||||
|
|
||||||
|
/* Max range — step higher (longer range / zoom out); Chain Home: no effect */
|
||||||
case GLFW_KEY_P:
|
case GLFW_KEY_P:
|
||||||
if (current_radar != RADAR_CHAIN_HOME) {
|
if (current_radar == RADAR_MARINE_ASCOPE) {
|
||||||
uniform_max_range = std::min(MAX_RANGE_MAX,
|
if (ascope_range_setting < MARINE_A_SCOPE_NUM_RANGES - 1) {
|
||||||
uniform_max_range + MAX_RANGE_STEP);
|
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;
|
break;
|
||||||
|
|
||||||
@@ -578,26 +656,33 @@ static void render_radar_list() {
|
|||||||
static void render_selection_status_bar() {
|
static void render_selection_status_bar() {
|
||||||
float x = MARGIN;
|
float x = MARGIN;
|
||||||
float y = static_cast<float>(STATUS_BAR_HEIGHT) - MARGIN - LH_MAIN;
|
float y = static_cast<float>(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,
|
g_text_renderer.render_text("Use ", x, y, 1.0f,
|
||||||
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
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,
|
g_text_renderer.render_text("1", xp, y, 1.0f,
|
||||||
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
||||||
xp += g_text_renderer.get_text_width("1", 1.0f);
|
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]);
|
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,
|
g_text_renderer.render_text("2", xp, y, 1.0f,
|
||||||
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
||||||
xp += g_text_renderer.get_text_width("2", 1.0f);
|
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]);
|
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,
|
g_text_renderer.render_text("ENTER", xp, y, 1.0f,
|
||||||
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
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,
|
g_text_renderer.render_text(" to activate.", xp, y, 1.0f,
|
||||||
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
||||||
|
|
||||||
|
/* Line 3: "Press ESC to exit the exhibit." */
|
||||||
y -= LH_MAIN;
|
y -= LH_MAIN;
|
||||||
g_text_renderer.render_text("Press ", x, y, 1.0f,
|
g_text_renderer.render_text("Press ", x, y, 1.0f,
|
||||||
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
||||||
xp = x + g_text_renderer.get_text_width("Press ", 1.0f);
|
xp = x + g_text_renderer.get_text_width("Press ", 1.0f);
|
||||||
|
|
||||||
g_text_renderer.render_text("ESC", xp, y, 1.0f,
|
g_text_renderer.render_text("ESC", xp, y, 1.0f,
|
||||||
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
COL_PINK[0], COL_PINK[1], COL_PINK[2]);
|
||||||
xp += g_text_renderer.get_text_width("ESC", 1.0f);
|
xp += g_text_renderer.get_text_width("ESC", 1.0f);
|
||||||
|
|
||||||
g_text_renderer.render_text(" to exit the exhibit.", xp, y, 1.0f,
|
g_text_renderer.render_text(" to exit the exhibit.", xp, y, 1.0f,
|
||||||
COL_WHITE[0], COL_WHITE[1], COL_WHITE[2]);
|
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;
|
current_radar = g_selectable[0].management_index;
|
||||||
g_active_radar = g_selectable[0].instance;
|
g_active_radar = g_selectable[0].instance;
|
||||||
g_app_state = AppState::OPERATING;
|
g_app_state = AppState::OPERATING;
|
||||||
|
reset_radar_controls(current_radar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user