// ==============================================================
//
// Orientation.cpp
//
// Determines orientation of GL-02 (harcoded for now) to us.
// Use with Delta-Glider scenario Smack!
//
// Real objective - provide demonstrator HUD hooking code using Enjo's new HUDDrawerSDK v0.1
//
// (c) Andrew Stokes (ADSWNJ) 2013 - licensed under LGPL
//
// All rights reserved
// ==============================================================
#define STRICT
#define ORBITER_MODULE
#include "windows.h"
#include "stdio.h"
#include "orbitersdk.h"
#include "Orientation.h"
// ==============================================================
// Global variables
int g_MFDmode; // identifier for new MFD mode
// ==============================================================
// API interface
DLLCLBK void InitModule (HINSTANCE hDLL)
{
static char *name = "Orientation"; // MFD mode name
MFDMODESPECEX spec;
spec.name = name;
spec.key = OAPI_KEY_T; // MFD mode selection key
spec.context = NULL;
spec.msgproc = Orientation::MsgProc; // MFD mode callback function
// Register the new MFD mode with Orbiter
g_MFDmode = oapiRegisterMFDMode (spec);
}
DLLCLBK void ExitModule (HINSTANCE hDLL)
{
// Unregister the custom MFD mode when the module is unloaded
oapiUnregisterMFDMode (g_MFDmode);
}
// ==============================================================
// MFD class implementation
// Constructor
Orientation::Orientation (DWORD w, DWORD h, VESSEL *vessel)
: MFD2 (w, h, vessel)
{
v = vessel;
hMyDock = v->GetDockHandle(0);
v->GetDockParams(hMyDock, dPos, dDir, dRot);
font = oapiCreateFont (w/20, true, "Fixed", FONT_NORMAL, 0);
// Add MFD initialisation here
hTgtV = oapiGetVesselByName("GL-02");
tv = oapiGetVesselInterface(hTgtV);
firstCalc = true;
}
// Destructor
Orientation::~Orientation ()
{
oapiReleaseFont (font);
// Add MFD cleanup code here
}
// HUD Drawing
bool Orientation::ShouldDrawHUD() const {
return true;
}
void Orientation::DrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad * skp) {
char buf[256];
int xPix, yPix;
union{
struct SKPCHARSIZE {
WORD ch;
WORD cw;
} s1;
DWORD s2;
} skpCS;
if (mode==HUD_NONE) return; // HUD is off, so no drawing
skp->Rectangle(hps->W-200,200,hps->W-20,400);
xPix = hps->W-195;
yPix = 205;
skpCS.s2 = skp->GetCharSize();
if (!firstCalc) {
skp->SetFont (font);
sprintf_s(buf, " Att Rate");
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(diffDir.y)<0.1) {
sprintf_s(buf, "Y %7.2f %6.3f ", diffDir.y, diffDirRate.y);
} else if (diffDir.y<0) {
sprintf_s(buf, "Y %7.2f %6.3f (yaw right)", diffDir.y, diffDirRate.y);
} else {
sprintf_s(buf, "Y %7.2f %6.3f (yaw left)", diffDir.y, diffDirRate.y);
}
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(diffDir.x)<0.1) {
sprintf_s(buf, "P %7.2f %6.3f ", diffDir.x, diffDirRate.x);
} else if (diffDir.x<0) {
sprintf_s(buf, "P %7.2f %6.3f (pitch up)", diffDir.x, diffDirRate.x);
} else {
sprintf_s(buf, "P %7.2f %6.3f (pitch down)", diffDir.x, diffDirRate.x);
}
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(diffDir.z)<0.1) {
sprintf_s(buf, "R %7.2f %6.3f ", diffDir.z, diffDirRate.z);
} else if (diffDir.z<0) {
sprintf_s(buf, "R %7.2f %6.3f (roll right)", diffDir.z, diffDirRate.z);
} else {
sprintf_s(buf, "R %7.2f %6.3f (roll left)", diffDir.z, diffDirRate.z);
}
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
yPix = yPix + skpCS.s1.ch + 2;
sprintf_s(buf, " Pos Vel");
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(relPos.x)<0.01) {
sprintf_s(buf, "X %7.2f %6.3f ", relPos.x, diffPos.x);
} else if (relPos.x>0) {
sprintf_s(buf, "X %7.2f %6.3f (go left)", relPos.x, diffPos.x);
} else {
sprintf_s(buf, "X %7.2f %6.3f (go right)", relPos.x, diffPos.x);
}
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(relPos.y)<0.01) {
sprintf_s(buf, "Y %7.2f %6.3f ", relPos.y, diffPos.y);
} else if (relPos.y>0) {
sprintf_s(buf, "Y %7.2f %6.3f (go down)", relPos.y, diffPos.y);
} else {
sprintf_s(buf, "Y %7.2f %6.3f (go up)", relPos.y, diffPos.y);
}
skp->Text (xPix, yPix, buf, strlen(buf));
yPix = yPix + skpCS.s1.ch + 2;
if (abs(relPos.z)<0.01) {
sprintf_s(buf, "Z %7.2f %6.3f ", -relPos.z, diffPos.z);
} else if (relPos.z>0) {
sprintf_s(buf, "Z %7.2f %6.3f (go backwards)", -relPos.z, diffPos.z);
} else {
sprintf_s(buf, "Z %7.2f %6.3f (go forwards)", -relPos.z, diffPos.z);
}
skp->Text (xPix, yPix, buf, strlen(buf));
}
}
// Return button labels
char *Orientation::ButtonLabel (int bt)
{
// The labels for the two buttons used by our MFD mode
static char *label[2] = {"UP", "DN"};
return (bt < 2 ? label[bt] : 0);
}
// Return button menus
int Orientation::ButtonMenu (const MFDBUTTONMENU **menu) const
{
// The menu descriptions for the two buttons
static const MFDBUTTONMENU mnu[2] = {
{"Move up", 0, '['},
{"Move down", 0, ']'}
};
if (menu) *menu = mnu;
return 2; // return the number of buttons used
}
// Repaint the MFD
bool Orientation::Update (oapi::Sketchpad *skp)
{
int l;
char buf[128];
Title (skp, "Orientation");
// Draws the MFD title
simT = oapiGetSimTime();
// Get oritnetaiotns, velocities and positions
v->GetGlobalOrientation(gblOri);
v->GetGlobalPos(gblPos);
v->GetGlobalVel(gblVel);
tv->GetGlobalPos(tvPos);
hDock = tv->GetDockHandle(0);
tv->GetDockParams(hDock, rtvdPos, rtvdDir, rtvdRot);
// Find our dock XYZ offset in local coords
tv->Local2Global(rtvdPos,gtvdPos); // Make remote coord tgt vehicle dock position into a global coord
v->Global2Local(gtvdPos,ltvdPos); // And flip it back into a local tgt vehicle coords
relPos = dPos - ltvdPos; // My dock Pos is already in local coords, so the relative offset is just one minus the other
// Find our Pitch Yaw offset in local coords
rtvdDir = rtvdPos - rtvdDir; // Turn direction vector into a point a unit distance inside the target dock, aligned correctly
tv->Local2Global(rtvdDir,gtvdDir); // Flip to global
v->Global2Local(gtvdDir,ltvdDir); // ... and back to local in our frame
ltvdDir = ltvdDir - ltvdPos; // Subtract the dock coords, to make the direction coord back into a vector (on our local origin)
// For roll offset, use the Rot vector
rtvdRot = rtvdPos + rtvdRot; // Turn the rotation vector into a point offset from the dock
tv->Local2Global(rtvdRot,gtvdRot); // Flip to global
v->Global2Local(gtvdRot,ltvdRot); // ... and back to local in our frame
ltvdRot = ltvdRot - ltvdPos; // Subtract the dock coords, to make the rotation coord back into a vector (on our local origin)
diffDir.x = DEG* (atan2(dDir.y, dDir.z) - atan2(ltvdDir.y, ltvdDir.z)); // DiffDir.x is PITCH
diffDir.y = DEG* (atan2(dDir.x, dDir.z) - atan2(ltvdDir.x, ltvdDir.z)); // DiffDir.y is YAW
diffDir.z = DEG * (atan2(ltvdRot.y, ltvdRot.x) - atan2(dRot.y, dRot.x)); // DiffDir.z is ROLL on the rotation alignment vector
if (diffDir.x < -180.0) diffDir.x += 360.0;
if (diffDir.y < -180.0) diffDir.y += 360.0;
if (diffDir.z < -180.0) diffDir.z += 360.0;
if (!firstCalc) {
simStep = simT - oldSimT;
diffPos = (relPos - oldRelPos) / simStep;
diffDirRate = (diffDir - oldDiffDir) / simStep;
skp->SetFont (font);
l = 2;
sprintf_s(buf, " Att Rate");
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(diffDir.y)<0.1) {
sprintf_s(buf, "Y %7.2f %6.3f ", diffDir.y, diffDirRate.y);
} else if (diffDir.y<0) {
sprintf_s(buf, "Y %7.2f %6.3f (yaw right)", diffDir.y, diffDirRate.y);
} else {
sprintf_s(buf, "Y %7.2f %6.3f (yaw left)", diffDir.y, diffDirRate.y);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(diffDir.x)<0.1) {
sprintf_s(buf, "P %7.2f %6.3f ", diffDir.x, diffDirRate.x);
} else if (diffDir.x<0) {
sprintf_s(buf, "P %7.2f %6.3f (pitch up)", diffDir.x, diffDirRate.x);
} else {
sprintf_s(buf, "P %7.2f %6.3f (pitch down)", diffDir.x, diffDirRate.x);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(diffDir.z)<0.1) {
sprintf_s(buf, "R %7.2f %6.3f ", diffDir.z, diffDirRate.z);
} else if (diffDir.z<0) {
sprintf_s(buf, "R %7.2f %6.3f (roll right)", diffDir.z, diffDirRate.z);
} else {
sprintf_s(buf, "R %7.2f %6.3f (roll left)", diffDir.z, diffDirRate.z);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
l++;
sprintf_s(buf, " Pos Vel");
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(relPos.x)<0.01) {
sprintf_s(buf, "X %7.2f %6.3f ", relPos.x, diffPos.x);
} else if (relPos.x>0) {
sprintf_s(buf, "X %7.2f %6.3f (go left)", relPos.x, diffPos.x);
} else {
sprintf_s(buf, "X %7.2f %6.3f (go right)", relPos.x, diffPos.x);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(relPos.y)<0.01) {
sprintf_s(buf, "Y %7.2f %6.3f ", relPos.y, diffPos.y);
} else if (relPos.y>0) {
sprintf_s(buf, "Y %7.2f %6.3f (go down)", relPos.y, diffPos.y);
} else {
sprintf_s(buf, "Y %7.2f %6.3f (go up)", relPos.y, diffPos.y);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
l++;
if (abs(relPos.z)<0.01) {
sprintf_s(buf, "Z %7.2f %6.3f ", -relPos.z, diffPos.z);
} else if (relPos.z>0) {
sprintf_s(buf, "Z %7.2f %6.3f (go backwards)", -relPos.z, diffPos.z);
} else {
sprintf_s(buf, "Z %7.2f %6.3f (go forwards)", -relPos.z, diffPos.z);
}
skp->Text (W*10/100, H*l/25, buf, strlen(buf));
} else {
firstCalc = false;
};
oldSimT = simT;
oldRelPos = relPos;
oldDiffDir = diffDir;
return true;
}
// MFD message parser
int Orientation::MsgProc (UINT msg, UINT mfd, WPARAM wparam, LPARAM lparam)
{
switch (msg) {
case OAPI_MSG_MFD_OPENED:
// Our new MFD mode has been selected, so we create the MFD and
// return a pointer to it.
return (int)(new Orientation (LOWORD(wparam), HIWORD(wparam), (VESSEL*)lparam));
}
return 0;
}