// ==============================================================
// ORBITER MODULE: ShuttlePB
// Part of the ORBITER SDK
// Copyright (C) 2002-2003 Martin Schweiger
// Copyright (C) 2003 Simon Proud
// All rights reserved
//
// ShuttlePB.cpp
// Control module for ShuttlePB vessel class
// ==============================================================
#include "c:\orbiter\orbitersdk\include\orbitersdk.h"
#include "shuttlepb.h"
const double PB_FUELMASS = 75000.0;
const double PB_ISP = 5e4;
const double PB_MAXMAINTH = 3e7;
const double PB_MAXHOVERTH = 1.5e4;
const double PB_MAXRCSTH = 2e2;
// Calculate lift coefficient [Cl] as a function of aoa (angle of attack) over -Pi ... Pi
// Implemented here as a piecewise linear function
double LiftCoeff (double aoa)
{
const int nlift = 9;
static const double AOA[nlift] = {-180*RAD,-60*RAD,-30*RAD,-1*RAD,15*RAD,20*RAD,25*RAD,60*RAD,180*RAD};
static const double CL[nlift] = { 0, 0, -0.1, 0, 0.2, 0.25, 0.2, 0, 0};
static const double SCL[nlift] = {(CL[1]-CL[0])/(AOA[1]-AOA[0]), (CL[2]-CL[1])/(AOA[2]-AOA[1]),
(CL[3]-CL[2])/(AOA[3]-AOA[2]), (CL[4]-CL[3])/(AOA[4]-AOA[3]),
(CL[5]-CL[4])/(AOA[5]-AOA[4]), (CL[6]-CL[5])/(AOA[6]-AOA[5]),
(CL[7]-CL[6])/(AOA[7]-AOA[6]), (CL[8]-CL[7])/(AOA[8]-AOA[7])};
for (int i = 0; i < nlift-1 && AOA[i+1] < aoa; i++);
return CL
+ (aoa-AOA)*SCL;
}
// ==============================================================
// API interface
// ==============================================================
// Initialisation
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
return new VESSEL (hvessel, flightmodel);
}
// Cleanup
DLLCLBK void ovcExit (VESSEL *vessel)
{
if (vessel) delete vessel;
}
// Set the capabilities of the vessel class
DLLCLBK void ovcSetClassCaps (VESSEL *vessel, FILEHANDLE cfg)
{
THRUSTER_HANDLE th, th_rcs[12], th_group[4];
// physical specs
vessel->SetSize (3.5);
vessel->SetEmptyMass (500.0);
//vessel->SetCOG_elev (1.5);
vessel->SetCW (0.3, 0.3, 0.6, 0.9);
vessel->SetWingAspect (0.7);
vessel->SetWingEffectiveness (2.5);
vessel->SetCrossSections (_V(10.5,15.0,5.);
vessel->SetRotDrag (_V(0.6,0.6,0.35));
if (vessel->GetFlightModel() >= 1) {
vessel->SetPitchMomentScale (1e-4);
vessel->SetBankMomentScale (1e-4);
}
vessel->SetPMI (_V(2.28,2.31,0.79));
vessel->SetTrimScale (0.05);
vessel->SetCameraOffset (_V(0,0.8,0));
vessel->SetLiftCoeffFunc (LiftCoeff);
vessel->SetDockParams (_V(0,1.3,-1), _V(0,1,0), _V(0,0,-1));
vessel->SetTouchdownPoints (_V(0,-1.5,2), _V(-1,-1.5,-1.5), _V(1,-1.5,-1.5));
// propellant resources
PROPELLANT_HANDLE hpr = vessel->CreatePropellantResource (PB_FUELMASS);
// thruster defintions
th = vessel->CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, hpr, PB_ISP);
vessel->CreateThrusterGroup (&th, 1, THGROUP_MAIN);
vessel->AddExhaust (th, 8, 1, _V(0,0.3,-4.35), _V(0,0,-1));
th = vessel->CreateThruster (_V(0,-1.5,0), _V(0,1,0), PB_MAXHOVERTH, hpr, PB_ISP);
vessel->CreateThrusterGroup (&th, 1, THGROUP_HOVER);
vessel->AddExhaust (th, 8, 1, _V(0,-1.5,1), _V(0,-1,0));
vessel->AddExhaust (th, 8, 1, _V(0,-1.5,-1), _V(0,-1,0));
th_rcs[ 0] = vessel->CreateThruster (_V( 1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 1] = vessel->CreateThruster (_V( 1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 2] = vessel->CreateThruster (_V(-1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 3] = vessel->CreateThruster (_V(-1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 4] = vessel->CreateThruster (_V( 1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 5] = vessel->CreateThruster (_V( 1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 6] = vessel->CreateThruster (_V(-1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 7] = vessel->CreateThruster (_V(-1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 8] = vessel->CreateThruster (_V( 1,0, 3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[ 9] = vessel->CreateThruster (_V(-1,0, 3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[10] = vessel->CreateThruster (_V( 1,0,-3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
th_rcs[11] = vessel->CreateThruster (_V(-1,0,-3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
th_group[0] = th_rcs[0];
th_group[1] = th_rcs[2];
th_group[2] = th_rcs[5];
th_group[3] = th_rcs[7];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);
th_group[0] = th_rcs[1];
th_group[1] = th_rcs[3];
th_group[2] = th_rcs[4];
th_group[3] = th_rcs[6];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);
th_group[0] = th_rcs[0];
th_group[1] = th_rcs[4];
th_group[2] = th_rcs[3];
th_group[3] = th_rcs[7];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKLEFT);
th_group[0] = th_rcs[1];
th_group[1] = th_rcs[5];
th_group[2] = th_rcs[2];
th_group[3] = th_rcs[6];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKRIGHT);
th_group[0] = th_rcs[0];
th_group[1] = th_rcs[4];
th_group[2] = th_rcs[2];
th_group[3] = th_rcs[6];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_UP);
th_group[0] = th_rcs[1];
th_group[1] = th_rcs[5];
th_group[2] = th_rcs[3];
th_group[3] = th_rcs[7];
vessel->CreateThrusterGroup (th_group, 4, THGROUP_ATT_DOWN);
th_group[0] = th_rcs[8];
th_group[1] = th_rcs[11];
vessel->CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);
th_group[0] = th_rcs[9];
th_group[1] = th_rcs[10];
vessel->CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);
th_group[0] = th_rcs[8];
th_group[1] = th_rcs[10];
vessel->CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);
th_group[0] = th_rcs[9];
th_group[1] = th_rcs[11];
vessel->CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);
// visual specs
vessel->AddMesh ("ShuttlePB");
}
#define LOADBMP(id) (LoadBitmap (g_Param.hDLL, MAKEINTRESOURCE (id)))
struct {
HINSTANCE hDLL;
HFONT font[2];
HPEN pen[2];
} g_Param;
void ShuttlePB::InitPanel (int panel)
{
switch (panel) {
case 0:
// srf[0] = oapiCreateSurface (LOADBMP (IDB_SWITCH));
//srf[1] = oapiCreateSurface (LOADBMP (IDB_LIGHT1));
//srf[2] = oapiCreateSurface (LOADBMP (IDB_LIGHT2));
//srf[3] = oapiCreateSurface (LOADBMP (IDB_LIGHT3));
break;
}
}
void ShuttlePB::RedrawPanel_Alt (VESSEL *vessel, SURFHANDLE surf)
{
double alpha;
double range = 270 * RAD;
range = range / 300000;
alpha = vessel->GetAltitude();
if (alpha > 300000) alpha = 300000;
alpha = 300000 - alpha;
HDC hDC = oapiGetDC (surf);
DrawNeedle (hDC, 40, 50, 45, (alpha * range)-(PI / 2), g_Param.pen[0], g_Param.pen[1] );
oapiReleaseDC (surf, hDC);
}
bool ShuttlePB::PanelRedrawEvent(VESSEL *vessel, int id, int event, SURFHANDLE surf)
{
switch (id) {
case AID_SWITCH:
if(!switch_autopilot) oapiBlt (surf, srf[0], 0, 0, 30, 0, 28, 23);
else oapiBlt (surf, srf[0], 0, 0, 57, 0, 28, 23);
return true;
case AID_NEEDLE:
RedrawPanel_Alt (vessel, surf);
return true;
case AID_VEL:
RedrawPanel_Vel (vessel, surf);
return true;
case AID_PRES:
RedrawPanel_Pres (vessel, surf);
return true;
case AID_FUEL:
RedrawPanel_Fuel (vessel, surf);
return true;
case AID_TIMER:
Redraw_Timer (surf);
return true;
case AID_PANEL_ORBIT:
RedrawPanel_Orbit (vessel, surf);
return true;
case AID_PROGRADE:
if (status==4)
{
if (prograde) oapiBlt (surf, srf[3], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[3], 0, 0, 0, 0, 46, 12);
}
return true;
case AID_RETROGRADE:
if (status==4)
{
if (retrograde) oapiBlt (surf, srf[3], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[3], 0, 0, 0, 0, 46, 12);
}
return true;
case AID_NORMAL:
if (status==4)
{
if (normal) oapiBlt (surf, srf[3], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[3], 0, 0, 0, 0, 46, 12);
}
return true;
case AID_ANORMAL:
if (status==4)
{
if (anormal) oapiBlt (surf, srf[3], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[3], 0, 0, 0, 0, 46, 12);
}
return true;
case AID_FIRE:
if (switch_retro) oapiBlt (surf, srf[0], 0, 0, 57, 0, 28, 23);
else oapiBlt (surf, srf[0], 0, 0, 30, 0, 28, 23);
return true;
case AID_FIRE2:
if (fire) oapiBlt (surf, srf[1], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[1], 0, 0, 0, 0, 46, 12);
return true;
case AID_STAGE1:
if ((status==0) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05)) oapiBlt (surf, srf[2], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[2], 0, 0, 0, 0, 46, 12);
return true;
case AID_STAGE2:
if (((status==0) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05)) || ((status==1) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05)) || ((status==2) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05))) oapiBlt (surf, srf[2], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[2], 0, 0, 0, 0, 46, 12);
return true;
case AID_STAGE3:
if (((status==3) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05))) oapiBlt (surf, srf[2], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[2], 0, 0, 0, 0, 46, 12);
return true;
case AID_STAGE4:
if (((status==4) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05))) oapiBlt (surf, srf[2], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[2], 0, 0, 0, 0, 46, 12);
return true;
case AID_STAGE5:
if (((status==5) &&(vessel->GetEngineLevel(ENGINE_MAIN)>.05))) oapiBlt (surf, srf[2], 0, 0, 46, 0, 46, 12);
else oapiBlt (surf, srf[2], 0, 0, 0, 0, 46, 12);
return true;
case AID_EJECT:
if(!switch_ejected) oapiBlt (surf, srf[0], 0, 0, 30, 0, 28, 23);
else oapiBlt (surf, srf[0], 0, 0, 57, 0, 28, 23);
return true;
}
return false;
}
bool ShuttlePB::PanelMouseEvent(VESSEL *vessel, int id, int event, int mx, int my)
{
switch (id) {
case AID_SWITCH:
if(!guidance) {
guidance = true;
switch_autopilot=true;
}
else {
guidance = false;
switch_autopilot=false;
}
return true;
case AID_FIRE:
if (status==4)
{
if (vessel->GetThrusterGroupLevel(thg_ShuttlePB) == 0.0)
{
fire=true;
switch_retro=true;
vessel->SetThrusterGroupLevel (thg_ShuttlePB,1.0);
}
else
{
fire=false;
switch_retro=false;
vessel->SetThrusterGroupLevel (thg_ShuttlePB,0.0);
}
}
else if (switch_retro==false) switch_retro=true;
else if (switch_retro==true) switch_retro=false;
return true;
case AID_EJECT:
if(!ejected && status==4) {
ejected = true;
switch_ejected=true;
SeparateStage (vessel, status);
stage = 5;
}
else if (switch_ejected==true) switch_ejected=false;
else if (switch_ejected==false) switch_ejected=true;
return true;
}
return false;
}
bool ShuttlePB::LoadPanel (VESSEL *vessel, int id)
{
ReleaseSurfaces();
if (id != 0) return false;
static MFDSPEC mfds_left = {{205,140, 320, 265}, 6, 6, 47, 41};
HBITMAP hBmp = LoadBitmap (g_Param.hDLL, MAKEINTRESOURCE (IDB_PANEL1));
oapiRegisterPanelBackground (hBmp, PANEL_ATTACH_BOTTOM|PANEL_MOVEOUT_BOTTOM, 0xffffff);
oapiRegisterMFD (MFD_LEFT, mfds_left);
oapiRegisterPanelArea (AID_SWITCH, _R(405, 215, 435, 245), PANEL_REDRAW_MOUSE, PANEL_MOUSE_LBDOWN, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_NEEDLE, _R(110, 465, 200, 555), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_PROGRADE, _R(600, 222, 648, 234), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_RETROGRADE, _R(661, 222, 707, 234), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_NORMAL, _R(600, 257, 648, 270), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_ANORMAL, _R(661, 257, 707, 270), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_FIRE, _R(445, 215, 475, 245), PANEL_REDRAW_MOUSE, PANEL_MOUSE_LBDOWN, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_FIRE2, _R(600, 329, 648, 341), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_TIMER, _R(442, 63, 486, 82), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_VEL, _R(275, 355, 360, 445), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_PRES, _R(610, 470, 700, 560), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_FUEL, _R(440, 360, 525, 445), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_STAGE1, _R(600, 42, 648, 54), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_STAGE2, _R(661, 42, 707, 54), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_STAGE3, _R(600, 77, 648, 89), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_STAGE4, _R(661, 77, 707, 89), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_STAGE5, _R(600, 114, 648, 126), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_EJECT, _R(485, 215, 515, 245), PANEL_REDRAW_MOUSE, PANEL_MOUSE_LBDOWN, PANEL_MAP_BACKGROUND);
oapiRegisterPanelArea (AID_PANEL_ORBIT, _R(180, 45, 345, 85), PANEL_REDRAW_ALWAYS, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND);
InitPanel (id);
return hBmp != NULL;
}
BOOL WINAPI DllMain (HINSTANCE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
int i;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
g_Param.hDLL = hModule;
g_Param.font[0] = CreateFont (-13, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, "Arial");
g_Param.font[1] = CreateFont (-10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Arial");
g_Param.pen[0] = CreatePen (PS_SOLID, 1, RGB(252, 252, 252));
g_Param.pen[1] = CreatePen (PS_SOLID, 3, RGB(164,164,164));
break;
case DLL_PROCESS_DETACH:
for (i = 0; i < 2; i++) DeleteObject (g_Param.font);
for (i = 0; i < 2; i++) DeleteObject (g_Param.pen);
break;
}
return TRUE;
}
DLLCLBK bool ovcLoadPanel (VESSEL *vessel, int id)
{
ShuttlePB* ShuttlePB = (ShuttlePB*)vessel;
return ShuttlePB->LoadPanel( ShuttlePB, id );
}
DLLCLBK bool ovcPanelMouseEvent (VESSEL *vessel, int id, int event, int mx, int my)
{
ShuttlePB* ShuttlePB = (ShuttlePB*)vessel;
return ShuttlePB->PanelMouseEvent( ShuttlePB, id, event, mx, my );
}
DLLCLBK bool ovcPanelRedrawEvent (VESSEL *vessel, int id, int event, SURFHANDLE surf)
{
ShuttlePB* ShuttlePB = (ShuttlePB*)vessel;
return ShuttlePB->PanelRedrawEvent( ShuttlePB, id, event, surf);
}