xp12camera
Owner: IIIlllIIIllI URL: git@github.com:nyangkosense/xp12camera.git
6
Commit 558318ce2bf46c8ecceb0c22217009971e9ab4ab by SM <seb.michalk@gmail.com> on 2025-06-25 15:06:06 +0200
diff --git a/FLIR_Camera.cpp b/FLIR_Camera.cpp
index a631582..73cc058 100644
--- a/FLIR_Camera.cpp
+++ b/FLIR_Camera.cpp
@@ -43,6 +43,7 @@
static XPLMHotKeyID gTiltUpKey = NULL;
static XPLMHotKeyID gTiltDownKey = NULL;
static XPLMHotKeyID gThermalToggleKey = NULL;
+static XPLMHotKeyID gFocusLockKey = NULL;
// Aircraft position datarefs
static XPLMDataRef gPlaneX = NULL;
@@ -65,7 +66,8 @@ static int gDrawCallbackRegistered = 0;
static int gThermalMode = 1; // 0=Off, 1=White Hot, 2=Enhanced
// Target tracking and object detection
- // static int gTargetLocked = 0; // unused
+ 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
@@ -110,6 +112,11 @@ static XPLMDataRef gAIAircraftX = NULL;
static XPLMDataRef gAIAircraftY = NULL;
static XPLMDataRef gAIAircraftZ = NULL;
static XPLMDataRef gAIAircraftCount = NULL;
+static XPLMDataRef gLocalDate = NULL;
+static XPLMDataRef gZuluTime = NULL;
+static XPLMDataRef gLatitude = NULL;
+static XPLMDataRef gLongitude = NULL;
+static XPLMDataRef gAltitude = NULL;
// Function declarations
static void ActivateFLIRCallback(void* inRefcon);
@@ -120,6 +127,7 @@ static XPLMDataRef gAIAircraftCount = NULL;
static void TiltUpCallback(void* inRefcon);
static void TiltDownCallback(void* inRefcon);
static void ThermalToggleCallback(void* inRefcon);
+static void FocusLockCallback(void* inRefcon);
static int FLIRCameraFunc(XPLMCameraPosition_t* outCameraPosition,
int inIsLosingControl,
@@ -165,6 +173,13 @@ static float GetDistanceToCamera(float x, float y, float z);
gAIAircraftY = XPLMFindDataRef("sim/multiplayer/position/plane1_y");
gAIAircraftZ = XPLMFindDataRef("sim/multiplayer/position/plane1_z");
gAIAircraftCount = XPLMFindDataRef("sim/operation/prefs/mult_max");
+
+ // Additional datarefs for HUD display
+ gLocalDate = XPLMFindDataRef("sim/time/local_date_days");
+ gZuluTime = XPLMFindDataRef("sim/time/zulu_time_sec");
+ gLatitude = XPLMFindDataRef("sim/flightmodel/position/latitude");
+ gLongitude = XPLMFindDataRef("sim/flightmodel/position/longitude");
+ gAltitude = XPLMFindDataRef("sim/flightmodel/position/elevation");
// Register hotkeys
gActivateKey = XPLMRegisterHotKey(XPLM_VK_F9, xplm_DownFlag,
@@ -202,11 +217,15 @@ static float GetDistanceToCamera(float x, float y, float z);
XPLMDebugString("FLIR Camera System: Plugin loaded successfully\n");
XPLMDebugString("FLIR Camera System: Press F9 to activate camera\n");
- XPLMDebugString("FLIR Camera System: Use +/- for zoom, arrows for pan/tilt, T for thermal\n");
+ XPLMDebugString("FLIR Camera System: Use +/- for zoom, arrows for pan/tilt, T for thermal, SPACE for focus lock\n");
gThermalToggleKey = XPLMRegisterHotKey(XPLM_VK_T, xplm_DownFlag,
"FLIR Thermal Toggle",
ThermalToggleCallback, NULL);
+
+ gFocusLockKey = XPLMRegisterHotKey(XPLM_VK_SPACE, xplm_DownFlag,
+ "FLIR Focus/Lock Target",
+ FocusLockCallback, NULL);
return 1;
}
@@ -221,6 +240,8 @@ static float GetDistanceToCamera(float x, float y, float z);
if (gPanRightKey) XPLMUnregisterHotKey(gPanRightKey);
if (gTiltUpKey) XPLMUnregisterHotKey(gTiltUpKey);
if (gTiltDownKey) XPLMUnregisterHotKey(gTiltDownKey);
+ if (gThermalToggleKey) XPLMUnregisterHotKey(gThermalToggleKey);
+ if (gFocusLockKey) XPLMUnregisterHotKey(gFocusLockKey);
// Stop camera control if active
if (gCameraActive) {
@@ -296,10 +317,10 @@ static float GetDistanceToCamera(float x, float y, float z);
static void PanLeftCallback(void* inRefcon)
{
if (gCameraActive) {
- gCameraPan -= 10.0f;
+ gCameraPan -= 2.0f; // More precise control
if (gCameraPan < -180.0f) gCameraPan += 360.0f;
char msg[256];
- sprintf(msg, "FLIR Camera System: Pan %.0f degrees\n", gCameraPan);
+ sprintf(msg, "FLIR Camera System: Pan %.1f degrees\n", gCameraPan);
XPLMDebugString(msg);
}
}
@@ -307,10 +328,10 @@ static float GetDistanceToCamera(float x, float y, float z);
static void PanRightCallback(void* inRefcon)
{
if (gCameraActive) {
- gCameraPan += 10.0f;
+ gCameraPan += 2.0f; // More precise control
if (gCameraPan > 180.0f) gCameraPan -= 360.0f;
char msg[256];
- sprintf(msg, "FLIR Camera System: Pan %.0f degrees\n", gCameraPan);
+ sprintf(msg, "FLIR Camera System: Pan %.1f degrees\n", gCameraPan);
XPLMDebugString(msg);
}
}
@@ -318,9 +339,9 @@ static float GetDistanceToCamera(float x, float y, float z);
static void TiltUpCallback(void* inRefcon)
{
if (gCameraActive) {
- gCameraTilt = fminf(gCameraTilt + 10.0f, 45.0f);
+ gCameraTilt = fminf(gCameraTilt + 2.0f, 45.0f); // More precise control
char msg[256];
- sprintf(msg, "FLIR Camera System: Tilt %.0f degrees\n", gCameraTilt);
+ sprintf(msg, "FLIR Camera System: Tilt %.1f degrees\n", gCameraTilt);
XPLMDebugString(msg);
}
}
@@ -328,9 +349,9 @@ static float GetDistanceToCamera(float x, float y, float z);
static void TiltDownCallback(void* inRefcon)
{
if (gCameraActive) {
- gCameraTilt = fmaxf(gCameraTilt - 10.0f, -90.0f);
+ gCameraTilt = fmaxf(gCameraTilt - 2.0f, -90.0f); // More precise control
char msg[256];
- sprintf(msg, "FLIR Camera System: Tilt %.0f degrees\n", gCameraTilt);
+ sprintf(msg, "FLIR Camera System: Tilt %.1f degrees\n", gCameraTilt);
XPLMDebugString(msg);
}
}
@@ -421,7 +442,9 @@ static float GetDistanceToCamera(float x, float y, float z);
// Debug output to verify callback is being called
static int callCount = 0;
if (callCount < 5) {
- XPLMDebugString("FLIR Camera System: DrawThermalOverlay called\n");
+ char debugMsg[256];
+ sprintf(debugMsg, "FLIR Camera System: DrawThermalOverlay called, thermal mode: %d\n", gThermalMode);
+ XPLMDebugString(debugMsg);
callCount++;
}
@@ -490,59 +513,115 @@ static float GetDistanceToCamera(float x, float y, float z);
glVertex2f(centerX + bracketSize, centerY - bracketSize + 20);
glEnd();
- // Draw thermal effects based on thermal mode
+ // Draw thermal effects based on thermal mode - using same reliable approach as crosshair
if (gThermalMode > 0) {
+ if (callCount < 3) {
+ char debugMsg[256];
+ sprintf(debugMsg, "FLIR: Drawing thermal overlay mode %d\n", gThermalMode);
+ XPLMDebugString(debugMsg);
+ }
+
+ // Full-screen thermal overlay using same drawing method as crosshair
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ // Draw thermal background overlay
if (gThermalMode == 1) {
- // White Hot mode - dark background with bright heat sources
- if (callCount < 3) {
- char debugMsg[256];
- sprintf(debugMsg, "FLIR: Drawing thermal mode %d\n", gThermalMode);
- XPLMDebugString(debugMsg);
- }
-
- glColor4f(0.0f, 0.0f, 0.1f, 0.4f); // Make less opaque for testing
- glBegin(GL_QUADS);
- glVertex2f(0, 0);
- glVertex2f(screenWidth, 0);
- glVertex2f(screenWidth, screenHeight);
- glVertex2f(0, screenHeight);
- glEnd();
- } else if (gThermalMode == 2) {
- // Enhanced mode - blue tint with enhanced contrast
- glColor4f(0.1f, 0.3f, 0.6f, 0.3f); // Make less opaque for testing
- glBegin(GL_QUADS);
- glVertex2f(0, 0);
- glVertex2f(screenWidth, 0);
- glVertex2f(screenWidth, screenHeight);
- glVertex2f(0, screenHeight);
+ // White Hot mode - dark blue/black background
+ glColor4f(0.05f, 0.1f, 0.2f, 0.7f); // More opaque for realistic IR view
+ } else {
+ // Enhanced mode - greenish IR background
+ glColor4f(0.1f, 0.3f, 0.1f, 0.6f);
+ }
+
+ glBegin(GL_QUADS);
+ glVertex2f(0, 0);
+ glVertex2f(screenWidth, 0);
+ glVertex2f(screenWidth, screenHeight);
+ glVertex2f(0, screenHeight);
+ glEnd();
+
+ // Add IR noise effect using same line drawing approach
+ float time = XPLMGetElapsedTime();
+ glLineWidth(1.0f);
+
+ // 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) {
+ glBegin(GL_LINES);
+ glVertex2f(0, y);
+ glVertex2f(screenWidth, y);
glEnd();
}
- // Draw realistic heat sources based on actual detected objects
- // Draw some simple test heat sources first to verify basic thermal rendering
+ // Draw prominent heat sources using line-based approach for better visibility
+ glLineWidth(3.0f);
for (int i = 0; i < 4; i++) {
float x = (i + 1) * screenWidth / 5.0f;
float y = screenHeight / 2.0f;
- float size = 30.0f;
+ float size = 40.0f; // Make bigger
if (gThermalMode == 1) {
- // White hot - bright white
- glColor4f(1.0f, 1.0f, 1.0f, 0.9f);
+ // White hot - very bright white
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
} else {
- // Enhanced mode - bright orange
- glColor4f(1.0f, 0.8f, 0.0f, 0.9f);
+ // Enhanced mode - bright orange/yellow
+ glColor4f(1.0f, 0.9f, 0.2f, 1.0f);
}
- 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();
+ // Draw heat source as filled area using lines for better visibility
+ for (float dy = -size/2; dy < size/2; dy += 2.0f) {
+ glBegin(GL_LINES);
+ glVertex2f(x - size/2, y + dy);
+ glVertex2f(x + size/2, y + dy);
+ glEnd();
+ }
+
+ // Add heat glow effect
+ glLineWidth(1.0f);
+ float glowSize = size * 1.5f;
+ if (gThermalMode == 1) {
+ glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
+ } else {
+ glColor4f(0.8f, 0.6f, 0.1f, 0.6f);
+ }
+
+ // Draw glow as concentric rectangles
+ for (int ring = 0; ring < 3; ring++) {
+ float ringSize = glowSize + ring * 8.0f;
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x - ringSize/2, y - ringSize/2);
+ glVertex2f(x + ringSize/2, y - ringSize/2);
+ glVertex2f(x + ringSize/2, y + ringSize/2);
+ glVertex2f(x - ringSize/2, y + ringSize/2);
+ glEnd();
+ }
}
// Draw realistic heat sources if we have any
@@ -551,7 +630,7 @@ static float GetDistanceToCamera(float x, float y, float z);
}
// Also draw some simulated background thermal noise
- float time = XPLMGetElapsedTime();
+ // 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;
@@ -580,18 +659,281 @@ static float GetDistanceToCamera(float x, float y, float z);
glDisable(GL_BLEND);
}
- // Draw HUD info
- glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
+ // Draw military-style HUD overlay using line graphics
+ glColor4f(0.0f, 1.0f, 0.0f, 0.9f);
+ glLineWidth(2.0f);
+
+ // Draw HUD frame border
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(20, 20);
+ glVertex2f(screenWidth - 20, 20);
+ glVertex2f(screenWidth - 20, screenHeight - 20);
+ glVertex2f(20, screenHeight - 20);
+ glEnd();
+
+ // Draw corner brackets
+ float bracketLen = 30.0f;
+ glBegin(GL_LINES);
+ // Top-left corner
+ glVertex2f(20, 20 + bracketLen); glVertex2f(20, 20); glVertex2f(20, 20); glVertex2f(20 + bracketLen, 20);
+ // Top-right corner
+ glVertex2f(screenWidth - 20 - bracketLen, 20); glVertex2f(screenWidth - 20, 20);
+ glVertex2f(screenWidth - 20, 20); glVertex2f(screenWidth - 20, 20 + bracketLen);
+ // Bottom-left corner
+ glVertex2f(20, screenHeight - 20 - bracketLen); glVertex2f(20, screenHeight - 20);
+ glVertex2f(20, screenHeight - 20); glVertex2f(20 + bracketLen, screenHeight - 20);
+ // Bottom-right corner
+ glVertex2f(screenWidth - 20 - bracketLen, screenHeight - 20); glVertex2f(screenWidth - 20, screenHeight - 20);
+ glVertex2f(screenWidth - 20, screenHeight - 20); glVertex2f(screenWidth - 20, screenHeight - 20 - bracketLen);
+ glEnd();
+
+ // Draw data readouts using simple line graphics (simulating text)
+ // float lineHeight = 15.0f; // Currently unused but may be needed for future text spacing
+ float dataStartY = screenHeight - 80.0f;
+
+ // Get current aircraft data
+ float planeX = XPLMGetDataf(gPlaneX);
+ float planeY = XPLMGetDataf(gPlaneY);
+ float planeZ = XPLMGetDataf(gPlaneZ);
+ float planeHeading = XPLMGetDataf(gPlaneHeading);
+ 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);
+
+ glLineWidth(1.0f);
+
+ // UTC Time display (top-left)
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(30, dataStartY + 60);
+ glVertex2f(180, dataStartY + 60);
+ glVertex2f(180, dataStartY + 20);
+ glVertex2f(30, dataStartY + 20);
+ glEnd();
+
+ // Draw "UTC" label using simple lines
+ glBegin(GL_LINES);
+ // U
+ glVertex2f(40, dataStartY + 50); glVertex2f(40, dataStartY + 30);
+ glVertex2f(40, dataStartY + 30); glVertex2f(50, dataStartY + 30);
+ glVertex2f(50, dataStartY + 30); glVertex2f(50, dataStartY + 50);
+ // T
+ glVertex2f(60, dataStartY + 50); glVertex2f(80, dataStartY + 50);
+ glVertex2f(70, dataStartY + 50); glVertex2f(70, dataStartY + 30);
+ // C
+ glVertex2f(90, dataStartY + 50); glVertex2f(90, dataStartY + 30);
+ glVertex2f(90, dataStartY + 50); glVertex2f(105, dataStartY + 50);
+ glVertex2f(90, dataStartY + 30); glVertex2f(105, dataStartY + 30);
+
+ // Time digits - simple representation
+ float timeX = 120;
+ for (int i = 0; i < 4; i++) {
+ int digit;
+ if (i == 0) digit = hours / 10;
+ else if (i == 1) digit = hours % 10;
+ else if (i == 2) digit = minutes / 10;
+ else digit = minutes % 10;
+
+ // Draw digit as simple pattern
+ glVertex2f(timeX + i*12, dataStartY + 45);
+ glVertex2f(timeX + i*12 + 8, dataStartY + 45);
+ glVertex2f(timeX + i*12, dataStartY + 35);
+ glVertex2f(timeX + i*12 + 8, dataStartY + 35);
+
+ if (i == 1) { // Add colon after hours
+ glVertex2f(timeX + i*12 + 10, dataStartY + 42);
+ glVertex2f(timeX + i*12 + 10, dataStartY + 38);
+ }
+ }
+ glEnd();
+
+ // Position display (top-right)
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(screenWidth - 250, dataStartY + 60);
+ glVertex2f(screenWidth - 30, dataStartY + 60);
+ glVertex2f(screenWidth - 30, dataStartY + 20);
+ glVertex2f(screenWidth - 250, dataStartY + 20);
+ glEnd();
+
+ // Draw actual position data using line segments
+ glBegin(GL_LINES);
+ // LAT label
+ glVertex2f(screenWidth - 240, dataStartY + 50); glVertex2f(screenWidth - 240, dataStartY + 30);
+ glVertex2f(screenWidth - 240, dataStartY + 30); glVertex2f(screenWidth - 220, dataStartY + 30);
+
+ // Draw latitude value as segmented display
+ int latDegrees = (int)fabs(latitude);
+ int latMinutes = (int)((fabs(latitude) - latDegrees) * 60);
+ char latDir = (latitude >= 0) ? 'N' : 'S';
+
+ // Display latitude digits using line patterns
+ float latX = screenWidth - 200;
+ for (int i = 0; i < 2; i++) { // degrees
+ int digit = (i == 0) ? latDegrees / 10 : latDegrees % 10;
+ // Draw simple digit representation
+ if (digit > 0) {
+ glVertex2f(latX + i*15, dataStartY + 50);
+ glVertex2f(latX + i*15 + 10, dataStartY + 50);
+ }
+ glVertex2f(latX + i*15, dataStartY + 40);
+ glVertex2f(latX + i*15 + 10, dataStartY + 40);
+ }
+
+ // Longitude display (LON label)
+ glVertex2f(screenWidth - 240, dataStartY + 35); glVertex2f(screenWidth - 220, dataStartY + 35);
+ glVertex2f(screenWidth - 240, dataStartY + 25); glVertex2f(screenWidth - 220, dataStartY + 25);
+
+ // Display longitude digits
+ int lonDegrees = (int)fabs(longitude);
+ int lonMinutes = (int)((fabs(longitude) - lonDegrees) * 60);
+ char lonDir = (longitude >= 0) ? 'E' : 'W';
+
+ float lonX = screenWidth - 160;
+ for (int i = 0; i < 3; i++) { // longitude can be 3 digits
+ int digit;
+ if (i == 0) digit = lonDegrees / 100;
+ else if (i == 1) digit = (lonDegrees / 10) % 10;
+ else digit = lonDegrees % 10;
+
+ if (digit > 0 || i > 0) {
+ glVertex2f(lonX + i*12, dataStartY + 35);
+ glVertex2f(lonX + i*12 + 8, dataStartY + 35);
+ }
+ }
+
+ // Altitude display (ALT)
+ int altFeet = (int)(altitude * 3.28084f); // Convert meters to feet
+ glVertex2f(screenWidth - 100, dataStartY + 50); glVertex2f(screenWidth - 80, dataStartY + 50);
+ glVertex2f(screenWidth - 100, dataStartY + 40); glVertex2f(screenWidth - 80, dataStartY + 40);
+
+ // Display altitude digits (avoiding pow function)
+ int altDigits[5];
+ altDigits[0] = (altFeet / 10000) % 10;
+ altDigits[1] = (altFeet / 1000) % 10;
+ altDigits[2] = (altFeet / 100) % 10;
+ altDigits[3] = (altFeet / 10) % 10;
+ altDigits[4] = altFeet % 10;
+
+ for (int i = 0; i < 5; i++) {
+ if (altDigits[i] > 0 || altFeet >= 1000 || i >= 3) { // Show at least last 2 digits
+ glVertex2f(screenWidth - 75 + i*8, dataStartY + 45);
+ glVertex2f(screenWidth - 70 + i*8, dataStartY + 45);
+ }
+ }
+ glEnd();
+
+ // Camera status display (bottom-left)
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(30, dataStartY - 20);
+ glVertex2f(220, dataStartY - 20);
+ glVertex2f(220, dataStartY - 60);
+ glVertex2f(30, dataStartY - 60);
+ glEnd();
+
+ // Camera position relative to aircraft (using planeX, planeY, planeZ)
+ float cameraX = planeX + gCameraDistance * cosf(planeHeading * M_PI / 180.0f);
+ float cameraY = planeY + gCameraHeight;
+ float cameraZ = planeZ + gCameraDistance * sinf(planeHeading * M_PI / 180.0f);
+
+ // Distance from aircraft to camera mount
+ float mountDistance = sqrtf(gCameraDistance * gCameraDistance + gCameraHeight * gCameraHeight);
+
+ glBegin(GL_LINES);
+ // ZOOM label and bar
+ float zoomBarLength = gZoomLevel * 10.0f;
+ glVertex2f(40, dataStartY - 30);
+ glVertex2f(40 + zoomBarLength, dataStartY - 30);
+ glVertex2f(40, dataStartY - 35);
+ glVertex2f(40 + zoomBarLength, dataStartY - 35);
+
+ // Camera mount distance indicator (using calculated distance)
+ float distanceBar = (mountDistance / 10.0f) * 15.0f; // Scale for display
+ glVertex2f(40, dataStartY - 45);
+ glVertex2f(40 + distanceBar, dataStartY - 45);
+ glVertex2f(40, dataStartY - 50);
+ glVertex2f(40 + distanceBar, dataStartY - 50);
+
+ // Pan/Tilt indicators using actual values
+ float panIndicator = (gCameraPan + 180.0f) / 360.0f * 100.0f; // Normalize to 0-100
+ float tiltIndicator = (gCameraTilt + 90.0f) / 135.0f * 100.0f; // Normalize to 0-100
+
+ // Pan indicator
+ glVertex2f(120, dataStartY - 30);
+ glVertex2f(120 + panIndicator * 0.8f, dataStartY - 30);
- // Use X-Plane's text drawing (simplified for this example)
- char zoomText[64];
- sprintf(zoomText, "ZOOM: %.1fx", gZoomLevel);
+ // Tilt indicator
+ glVertex2f(120, dataStartY - 45);
+ glVertex2f(120 + tiltIndicator * 0.8f, dataStartY - 45);
+ glEnd();
+
+ // Target lock indicator (center-bottom)
+ if (gTargetLocked) {
+ glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // Red for locked
+ glLineWidth(3.0f);
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(centerX - 100, 80);
+ glVertex2f(centerX + 100, 80);
+ glVertex2f(centerX + 100, 40);
+ glVertex2f(centerX - 100, 40);
+ glEnd();
+
+ // Draw "LOCKED" indicator with simple graphics
+ glBegin(GL_LINES);
+ // Simple lines to represent "LOCKED" text
+ for (int i = 0; i < 5; i++) {
+ float x = centerX - 80 + i * 32;
+ glVertex2f(x, 65);
+ glVertex2f(x + 20, 65);
+ glVertex2f(x, 55);
+ glVertex2f(x + 20, 55);
+ }
+ glEnd();
+ }
+
+ // Range circles around center
+ glColor4f(0.0f, 1.0f, 0.0f, 0.3f);
+ glLineWidth(1.0f);
+ for (int i = 1; i <= 3; i++) {
+ float radius = 80.0f * i / gZoomLevel;
+ if (radius < screenWidth / 4) {
+ glBegin(GL_LINE_LOOP);
+ for (int angle = 0; angle < 360; angle += 10) {
+ float x = centerX + radius * cosf(angle * M_PI / 180.0f);
+ float y = centerY + radius * sinf(angle * M_PI / 180.0f);
+ glVertex2f(x, y);
+ }
+ glEnd();
+ }
+ }
+
+ // Heading indicator (top center)
+ glColor4f(0.0f, 1.0f, 0.0f, 0.9f);
+ glLineWidth(2.0f);
+ float headingX = centerX;
+ float headingY = screenHeight - 40;
- char panText[64];
- sprintf(panText, "PAN: %.0f° TILT: %.0f°", gCameraPan, gCameraTilt);
+ glBegin(GL_LINES);
+ // Heading scale
+ for (int h = 0; h < 360; h += 30) {
+ float angle = (h - planeHeading - gCameraPan) * M_PI / 180.0f;
+ float x1 = headingX + 100 * sinf(angle);
+ float x2 = headingX + 110 * sinf(angle);
+ if (x1 > 50 && x1 < screenWidth - 50) {
+ glVertex2f(x1, headingY);
+ glVertex2f(x2, headingY);
+ }
+ }
+ glEnd();
- // Position text in corners (actual text rendering would need XPLMDrawString)
- // This is just showing where the text would go
+ // Center heading marker
+ glBegin(GL_LINES);
+ glVertex2f(headingX, headingY - 10);
+ glVertex2f(headingX, headingY + 10);
+ glEnd();
// OpenGL state managed by X-Plane for Window phase
@@ -965,4 +1307,43 @@ static void DrawRealisticThermalOverlay(void)
}
glDisable(GL_BLEND);
+}
+
+static void FocusLockCallback(void* inRefcon)
+{
+ if (gCameraActive) {
+ if (!gTargetLocked) {
+ // Find nearest target to focus on
+ float nearestDistance = 999999.0f;
+ int nearestTarget = -1;
+
+ // Check heat sources for nearest aircraft
+ for (int i = 0; i < gHeatSourceCount; i++) {
+ if (gHeatSources[i].type == 0) { // Aircraft
+ float distance = GetDistanceToCamera(gHeatSources[i].x, gHeatSources[i].y, gHeatSources[i].z);
+ if (distance < nearestDistance && distance > 100.0f) { // Minimum 100m distance
+ nearestDistance = distance;
+ nearestTarget = i;
+ }
+ }
+ }
+
+ if (nearestTarget >= 0) {
+ gTargetLocked = 1;
+ gFocusDistance = nearestDistance;
+ char msg[256];
+ sprintf(msg, "FLIR Camera System: Target LOCKED at %.0fm\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");
+ }
+ } else {
+ // Unlock target
+ gTargetLocked = 0;
+ XPLMDebugString("FLIR Camera System: Target UNLOCKED\n");
+ }
+ }
}
\ No newline at end of file
diff --git a/FLIR_Camera.o b/FLIR_Camera.o
index d2e9fbb..a1a81ca 100644
Binary files a/FLIR_Camera.o and b/FLIR_Camera.o differ
diff --git a/build/FLIR_Camera/win_x64/FLIR_Camera.xpl b/build/FLIR_Camera/win_x64/FLIR_Camera.xpl
index c4e58d7..9ce5bbf 100755
Binary files a/build/FLIR_Camera/win_x64/FLIR_Camera.xpl and b/build/FLIR_Camera/win_x64/FLIR_Camera.xpl differ