xp12camera
Owner: IIIlllIIIllI URL: git@github.com:nyangkosense/xp12camera.git
8
Commit ba7eabe5e98e177bd93a3e5ddbc382ee5ee6f302 by SM <seb.michalk@gmail.com> on 2025-06-25 15:40:38 +0200
diff --git a/FLIR_Camera.cpp b/FLIR_Camera.cpp
index dfe6667..748ee02 100644
--- a/FLIR_Camera.cpp
+++ b/FLIR_Camera.cpp
@@ -68,10 +68,10 @@ static int gThermalMode = 1; // 0=Off, 1=White Hot, 2=Enhanced
// Target tracking and object detection
static int gTargetLocked = 0;
static float gFocusDistance = 1000.0f; // Distance to focused target
- // static float gTargetX = 0.0f; // unused
- // static float gTargetY = 0.0f; // unused
- // static float gTargetZ = 0.0f; // unused
- // static int gDetectedObjects = 0; // unused
+ static float gTargetX = 0.0f; // World position of locked target
+ static float gTargetY = 0.0f;
+ static float gTargetZ = 0.0f;
+ static int gLockedTargetIndex = -1; // Index of locked target in heat sources
// Aircraft tracking arrays (up to 20 aircraft)
static float gAircraftPositions[20][3]; // x, y, z positions
@@ -226,6 +226,8 @@ static float GetDistanceToCamera(float x, float y, float z);
gFocusLockKey = XPLMRegisterHotKey(XPLM_VK_SPACE, xplm_DownFlag,
"FLIR Focus/Lock Target",
FocusLockCallback, NULL);
+
+ // Note: For text display, use FlyWithLua to read standard X-Plane datarefs
return 1;
}
@@ -434,9 +436,31 @@ static float GetDistanceToCamera(float x, float y, float z);
outCameraPosition->y = planeY + rotatedY;
outCameraPosition->z = planeZ + rotatedZ;
- // Camera orientation - combine aircraft heading with camera pan/tilt
- outCameraPosition->heading = planeHeading + gCameraPan;
- outCameraPosition->pitch = gCameraTilt;
+ // Camera orientation - if locked, track target; otherwise manual control
+ if (gTargetLocked && gLockedTargetIndex >= 0 && gLockedTargetIndex < gHeatSourceCount) {
+ // Update target position from heat sources
+ gTargetX = gHeatSources[gLockedTargetIndex].x;
+ gTargetY = gHeatSources[gLockedTargetIndex].y;
+ gTargetZ = gHeatSources[gLockedTargetIndex].z;
+
+ // Calculate angle to target
+ float dx = gTargetX - outCameraPosition->x;
+ float dy = gTargetY - outCameraPosition->y;
+ float dz = gTargetZ - outCameraPosition->z;
+
+ // Calculate heading and pitch to target
+ float targetHeading = atan2f(dz, dx) * 180.0f / M_PI;
+ float groundDistance = sqrtf(dx*dx + dz*dz);
+ float targetPitch = -atan2f(dy, groundDistance) * 180.0f / M_PI;
+
+ // Track the target automatically
+ outCameraPosition->heading = targetHeading;
+ outCameraPosition->pitch = targetPitch;
+ } else {
+ // Manual camera control
+ outCameraPosition->heading = planeHeading + gCameraPan;
+ outCameraPosition->pitch = gCameraTilt;
+ }
outCameraPosition->roll = 0.0f; // Keep camera level
// Apply zoom - this is the key for real magnification!
@@ -573,38 +597,12 @@ static float GetDistanceToCamera(float x, float y, float z);
glVertex2f(0, screenHeight);
glEnd();
- // Add IR noise effect using same line drawing approach
- float time = XPLMGetElapsedTime();
+ // Realistic IR scan lines only (no random noise)
glLineWidth(1.0f);
+ glColor4f(0.0f, 0.0f, 0.0f, 0.15f);
- // Generate IR noise pattern
- for (int y = 0; y < screenHeight; y += 4) {
- for (int x = 0; x < screenWidth; x += 6) {
- float noise = (sinf(time * 2.0f + x * 0.01f + y * 0.008f) +
- cosf(time * 1.5f + x * 0.015f + y * 0.012f)) * 0.5f;
-
- if (gThermalMode == 1) {
- // White hot noise
- float intensity = 0.1f + noise * 0.15f;
- glColor4f(intensity, intensity, intensity * 0.9f, 0.8f);
- } else {
- // Enhanced mode noise - green tint
- float intensity = 0.15f + noise * 0.2f;
- glColor4f(intensity * 0.3f, intensity, intensity * 0.4f, 0.7f);
- }
-
- // Draw noise pixels as small lines
- glBegin(GL_LINES);
- glVertex2f(x, y);
- glVertex2f(x + 2, y);
- glEnd();
- }
- }
-
- // Add scan lines for authentic IR look
- glColor4f(0.0f, 0.0f, 0.0f, 0.2f);
- glLineWidth(1.0f);
- for (int y = 0; y < screenHeight; y += 3) {
+ // Horizontal scan lines like real IR cameras
+ for (int y = 0; y < screenHeight; y += 2) {
glBegin(GL_LINES);
glVertex2f(0, y);
glVertex2f(screenWidth, y);
@@ -618,32 +616,7 @@ static float GetDistanceToCamera(float x, float y, float z);
DrawRealisticThermalOverlay();
}
- // Also draw some simulated background thermal noise
- // Use the existing time variable from above
- for (int i = 0; i < 6; i++) {
- for (int j = 0; j < 4; j++) {
- float x = (i + 1) * screenWidth / 7.0f;
- float y = (j + 1) * screenHeight / 5.0f;
-
- float intensity = (sinf(time * 0.2f + i * 0.5f + j * 0.3f) + 1.0f) * 0.4f;
- float size = 12.0f + intensity * 20.0f;
-
- if (gThermalMode == 1) {
- // White hot
- glColor4f(1.0f, 1.0f, 0.9f, intensity * 0.9f);
- } else {
- // Enhanced mode
- glColor4f(1.0f, 0.8f, 0.2f, intensity * 0.8f);
- }
-
- glBegin(GL_QUADS);
- glVertex2f(x - size/2, y - size/2);
- glVertex2f(x + size/2, y - size/2);
- glVertex2f(x + size/2, y + size/2);
- glVertex2f(x - size/2, y + size/2);
- glEnd();
- }
- }
+ // No background thermal noise - cleaner IR view
glDisable(GL_BLEND);
}
@@ -669,86 +642,22 @@ static float GetDistanceToCamera(float x, float y, float z);
glVertex2f(screenWidth - 30, screenHeight - 30); glVertex2f(screenWidth - 30, screenHeight - 30 - reticleSize);
glEnd();
- // Professional FLIR HUD using actual text rendering
- // Get current aircraft data
- float latitude = XPLMGetDataf(gLatitude);
- float longitude = XPLMGetDataf(gLongitude);
- float altitude = XPLMGetDataf(gAltitude);
- float zuluTime = XPLMGetDataf(gZuluTime);
-
- // Convert Zulu time to hours:minutes
- int hours = (int)(zuluTime / 3600.0f) % 24;
- int minutes = (int)((zuluTime - hours * 3600) / 60.0f);
+ // Data will be exported to shared datarefs for FlyWithLua display
+ // For now, minimal built-in display only
// Use X-Plane's text rendering for professional look
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
- // Status display using simple line graphics (safer than XPLMDrawString in drawing callback)
- // Top status indicators - using geometric shapes instead of text to avoid crashes
-
- // UTC time indicator (top-left corner)
- glLineWidth(2.0f);
- glBegin(GL_LINES);
- // Simple time display as bars
- for (int i = 0; i < 4; i++) {
- int value = (i < 2) ? hours : minutes;
- int digit = (i % 2 == 0) ? value / 10 : value % 10;
- float x = 40 + i * 20;
- float height = 5 + digit * 2; // Height represents digit value
- glVertex2f(x, screenHeight - 25);
- glVertex2f(x, screenHeight - 25 + height);
- }
- glEnd();
-
- // Zoom level display (top-right corner)
- glBegin(GL_LINES);
- float zoomIndicator = gZoomLevel * 10.0f;
- glVertex2f(screenWidth - 100, screenHeight - 25);
- glVertex2f(screenWidth - 100 + zoomIndicator, screenHeight - 25);
- glVertex2f(screenWidth - 100, screenHeight - 30);
- glVertex2f(screenWidth - 100 + zoomIndicator, screenHeight - 30);
- glEnd();
-
- // Thermal mode indicator (simple colored bar)
- if (gThermalMode > 0) {
- glLineWidth(4.0f);
- if (gThermalMode == 1) glColor4f(1.0f, 1.0f, 1.0f, 0.8f); // White for White Hot
- else glColor4f(0.0f, 1.0f, 0.0f, 0.8f); // Green for Enhanced
-
- glBegin(GL_LINES);
- glVertex2f(30, screenHeight - 45);
- glVertex2f(80, screenHeight - 45);
- glEnd();
- glColor4f(0.0f, 1.0f, 0.0f, 0.8f); // Reset to green
- }
+ // Minimal status indicators (no confusing abstract lines)
+ // Only show essential info
- // Zoom level indicator (bottom-left, simple and clean)
+ // Zoom level indicator (bottom-left corner only)
glLineWidth(2.0f);
+ glColor4f(0.0f, 1.0f, 0.0f, 0.8f);
glBegin(GL_LINES);
- // Simple zoom bar
- float zoomBar = gZoomLevel * 20.0f;
+ float zoomBar = fminf(gZoomLevel * 5.0f, 100.0f); // Scale zoom to reasonable bar length
glVertex2f(30, 40);
glVertex2f(30 + zoomBar, 40);
- glVertex2f(30, 35);
- glVertex2f(30 + zoomBar, 35);
- glEnd();
-
- // Pan/Tilt position indicators (bottom-right)
- glLineWidth(1.0f);
- glBegin(GL_LINES);
- // Pan indicator - horizontal line that moves
- float panPos = (gCameraPan + 180.0f) / 360.0f * 100.0f;
- glVertex2f(screenWidth - 150, 40);
- glVertex2f(screenWidth - 50, 40);
- glVertex2f(screenWidth - 150 + panPos, 35);
- glVertex2f(screenWidth - 150 + panPos, 45);
-
- // Tilt indicator - vertical line that moves
- float tiltPos = (gCameraTilt + 90.0f) / 135.0f * 30.0f;
- glVertex2f(screenWidth - 30, 30);
- glVertex2f(screenWidth - 30, 60);
- glVertex2f(screenWidth - 35, 30 + tiltPos);
- glVertex2f(screenWidth - 25, 30 + tiltPos);
glEnd();
// Target lock indicator (minimal and professional)
@@ -1231,20 +1140,22 @@ static void FocusLockCallback(void* inRefcon)
if (nearestTarget >= 0) {
gTargetLocked = 1;
+ gLockedTargetIndex = nearestTarget;
gFocusDistance = nearestDistance;
+ gTargetX = gHeatSources[nearestTarget].x;
+ gTargetY = gHeatSources[nearestTarget].y;
+ gTargetZ = gHeatSources[nearestTarget].z;
char msg[256];
- sprintf(msg, "FLIR Camera System: Target LOCKED at %.0fm\n", gFocusDistance);
+ sprintf(msg, "FLIR Camera System: Target LOCKED at %.0fm - Camera will track automatically\n", gFocusDistance);
XPLMDebugString(msg);
} else {
- // No target found, just lock current view
- gTargetLocked = 1;
- gFocusDistance = 1000.0f;
- XPLMDebugString("FLIR Camera System: Focus LOCKED on current view\n");
+ XPLMDebugString("FLIR Camera System: No targets found for lock-on\n");
}
} else {
// Unlock target
gTargetLocked = 0;
- XPLMDebugString("FLIR Camera System: Target UNLOCKED\n");
+ gLockedTargetIndex = -1;
+ XPLMDebugString("FLIR Camera System: Target UNLOCKED - Manual control restored\n");
}
}
}
\ No newline at end of file
diff --git a/FLIR_Camera.o b/FLIR_Camera.o
index 197b6d0..510ca94 100644
Binary files a/FLIR_Camera.o and b/FLIR_Camera.o differ
diff --git a/FLIR_HUD.lua b/FLIR_HUD.lua
new file mode 100644
index 0000000..d426344
--- /dev/null
+++ b/FLIR_HUD.lua
@@ -0,0 +1,93 @@
+-- FLIR Camera HUD Display Script for FlyWithLua
+-- Place this file in X-Plane/Resources/plugins/FlyWithLua/Scripts/
+-- This provides professional text overlay for the FLIR camera system
+
+-- Only display when FLIR camera is active
+-- You can detect this by checking if the external view is active and camera controls are locked
+
+if PLANE_ICAO == nil then PLANE_ICAO = "UNKNOWN" end
+
+function draw_flir_hud()
+ -- Only draw when in external view (indicating FLIR might be active)
+ local view_type = XPLMGetDataf("sim/graphics/view/view_type")
+
+ if view_type == 1026 then -- External view
+ -- Get current aircraft data
+ local zulu_time = XPLMGetDataf("sim/time/zulu_time_sec")
+ local latitude = XPLMGetDataf("sim/flightmodel/position/latitude")
+ local longitude = XPLMGetDataf("sim/flightmodel/position/longitude")
+ local altitude_msl = XPLMGetDataf("sim/flightmodel/position/elevation")
+ local altitude_agl = XPLMGetDataf("sim/flightmodel/position/y_agl")
+ local ground_speed = XPLMGetDataf("sim/flightmodel/position/groundspeed")
+ local heading = XPLMGetDataf("sim/flightmodel/position/psi")
+
+ -- Convert zulu time to HH:MM format
+ local hours = math.floor(zulu_time / 3600) % 24
+ local minutes = math.floor((zulu_time % 3600) / 60)
+ local time_string = string.format("%02d:%02d UTC", hours, minutes)
+
+ -- Convert altitude to feet
+ local alt_feet = math.floor(altitude_msl * 3.28084)
+ local agl_feet = math.floor(altitude_agl * 3.28084)
+
+ -- Convert ground speed to knots
+ local speed_knots = math.floor(ground_speed * 1.94384)
+
+ -- Set text color to FLIR green
+ glColor4f(0.0, 1.0, 0.0, 1.0)
+
+ -- Top status line
+ local status_line = string.format("FLIR CAMERA %s %.4f°N %.4f°W %dft MSL %dft AGL",
+ time_string, latitude, math.abs(longitude), alt_feet, agl_feet)
+ draw_string(30, SCREEN_HEIGHT - 30, status_line)
+
+ -- Navigation data
+ local nav_line = string.format("HDG: %03d° SPD: %d kts GS: %.1f m/s",
+ math.floor(heading), speed_knots, ground_speed)
+ draw_string(30, SCREEN_HEIGHT - 50, nav_line)
+
+ -- Aircraft identification
+ local aircraft_line = string.format("ACFT: %s TAIL: %s",
+ PLANE_ICAO, get_aircraft_tailnumber())
+ draw_string(30, SCREEN_HEIGHT - 70, aircraft_line)
+
+ -- Mission timer (time since FLIR activation)
+ local mission_time = os.time() - (flir_start_time or os.time())
+ local mission_mins = math.floor(mission_time / 60)
+ local mission_secs = mission_time % 60
+ local mission_line = string.format("MISSION TIME: %02d:%02d", mission_mins, mission_secs)
+ draw_string(SCREEN_WIDTH - 250, SCREEN_HEIGHT - 30, mission_line)
+
+ -- Target information (if available)
+ draw_string(SCREEN_WIDTH - 250, SCREEN_HEIGHT - 50, "TGT: SCANNING...")
+
+ -- Camera status
+ local zoom_level = 1.0 -- Would read from plugin if dataref available
+ local thermal_mode = "WHT" -- Would read from plugin if dataref available
+ local camera_line = string.format("ZOOM: %.1fx THERMAL: %s", zoom_level, thermal_mode)
+ draw_string(30, 70, camera_line)
+
+ end
+end
+
+function get_aircraft_tailnumber()
+ local tailnum = XPLMGetDatab("sim/aircraft/view/acf_tailnum")
+ if tailnum and string.len(tailnum) > 0 then
+ return tailnum
+ else
+ return "UNKNOWN"
+ end
+end
+
+-- Initialize mission start time when script loads
+if flir_start_time == nil then
+ flir_start_time = os.time()
+end
+
+-- Register the drawing function
+do_every_draw("draw_flir_hud()")
+
+-- Add hotkey to reset mission timer
+add_macro("FLIR: Reset Mission Timer", "flir_start_time = os.time()", "", "")
+
+logMsg("FLIR HUD Display Script Loaded - Professional text overlay active")
\ No newline at end of file
diff --git a/build/FLIR_Camera/win_x64/FLIR_Camera.xpl b/build/FLIR_Camera/win_x64/FLIR_Camera.xpl
index bf95a02..ba35afb 100755
Binary files a/build/FLIR_Camera/win_x64/FLIR_Camera.xpl and b/build/FLIR_Camera/win_x64/FLIR_Camera.xpl differ