PART 14: Making the Cockpit Interactive
So last we left off we had a cockpit and a shiny cockpit control class that didn't actually do anything. Now it's time to do stuff.
VC displays and user inputs are handled by "Active areas" that are registered when the VC is loaded. To generate these active area s I have created a function called "RegisterActiveAreas" in our cockpit control class. (See part 13) this function is a void and takes a single VECTOR3 variable called "ofs" as an argument. If you look at the top of our "clbkLoadVC" back in the vessel class itself I think you can figure out what it's for.
Anyway, in order to function each active area needs to be assigned an index value and a location within the cockpit. The index value is a base 8 intiger and the location a VECTOR3. We could declare these Individually but for the sake of my sanity and because there are a whole lot of active areas in our cockpit I will be putting as much as I can into the Cockpit header file.
Observe...
That is a list of every switch, display, and button in our cockpit. each with a unique index number and 3D position assigned to it.
Yes it's a lot of information, but defining it once in the header file allows us to access it at will and will make what comes next a lot easier. Lets start with something simple, making the door open.
Open our RegisterActiveAreas function and add the following lines...
What we are doing here is creating two active areas. thier postions correlate to the positions of the EVA hatch's door handle when the door is open and when the door is closed. Let's break them down.
"oapiVCRegisterArea (AID_EVAHANDLE_OPEN, PANEL_REDRAW_NEVER, PANEL_MOUSE_DOWN);
"
This line is the initial declaration of the active area. "AID_EVAHANDLE_OPEN" is the index number as defined in our header file, "PANEL_REDRAW_NEVER" indicates that there are no "redraw events" associated with the active area. Redraw events are how the VC updates things like gauges and other displays. "PANEL_MOUSE_DOWN" means that the active area is activated when someone clicks on it (mouse button is down).
"oapiVCSetAreaClickmode_Spherical (AID_EVAHANDLE_CLOSE, _V( 0.3300,-0.4888, 0.9368) + ofs, 0.08);"
This line states what kind of active area we are dealing with and it's posittion within the cockpit. In this case the active area is a spherical zone 0.08 units in diameter (8 cm) at the position indicated.
Now that we have an active area it's time to assign a function to it.
In the vessel class itself parsing of cockpit inputs is handled by "clbkVCMouseEvent" to serve this purpose you will see that I have placed a function called "MouseEvent" in our cockpit control class.
In it I have placed the following lines...
When the user clicks on an active area Orbiter automatically passes the index number of the area to the mouse event parser, the "id" variable in the above code. The parser then compares that id number to it's list of possibles contained in the "switch (id)" function. If it finds a match it performs the assigned function and returns true, otherwise it returns false.
In this case the functions and their purpose should be readily apparent.
NOTE: v-> is a interface that allows us to manipulate data/call functions from our parent vessel as described in part 13.
Now that we have the some active areas registered and some lines for our parser to chew on we need to add them to our simulation. Our cockpit is not actually a vessel, planet, mfd, or somesuch and as such Orbiter will ignore it unless we specifically tell it otherwise.
To do this we need to go back to our lunar module's code and add calls for the cockpit's functions.
In ClbkLoadVC add a call to register our active areas.
Then to handle our mouse events overload "clbkVCMouseEvent" and add the following line.
The active areas should now be registered in orbiter and user inputs will be passed to the cockpit control class to be parsed.
Compile and test your handy work. clicking on the hatch handle in the VC should now cause the hatch to open or close.
NEXT UP: Animated Switches.
So last we left off we had a cockpit and a shiny cockpit control class that didn't actually do anything. Now it's time to do stuff.
VC displays and user inputs are handled by "Active areas" that are registered when the VC is loaded. To generate these active area s I have created a function called "RegisterActiveAreas" in our cockpit control class. (See part 13) this function is a void and takes a single VECTOR3 variable called "ofs" as an argument. If you look at the top of our "clbkLoadVC" back in the vessel class itself I think you can figure out what it's for.
Anyway, in order to function each active area needs to be assigned an index value and a location within the cockpit. The index value is a base 8 intiger and the location a VECTOR3. We could declare these Individually but for the sake of my sanity and because there are a whole lot of active areas in our cockpit I will be putting as much as I can into the Cockpit header file.
Observe...
Code:
// ==============================================================
// Active Area Definitions
// ==============================================================
// Multi Function Display indexes
#define CmdMFD 00 // Primary (Panel 4) MFD
// Main Panel Displays and Gauges
#define AID_LCD_DATETIME 0001 // Main panel digital clock
#define AID_LCD_FUEL 0002 // Main engine digital propellant readout
#define AID_LCD_RCS 0003 // RCS thruster digital propellant readout
#define AID_LCD_DELTAV 0004 // dV digital display
#define AID_GAUGE_ALTRANGE 0005 // Altitude/Range indicator
#define AID_GAUGE_RANGERATE 0006 // Range Rate indicator
#define AID_GAUGE_VACC 0007 // Vertical acceleration (T/W) indicator
#define AID_CAUTIONADVISORY 0010 // Caution/Warning/Advisory (CWA) Display
#define AID_P1_MASTERCAUTION 0011 // Commander's master Caution Indicator
#define AID_P2_MASTERCAUTION 0012 // Pilot's master Caution Indicator
#define AID_P1_XPOINTER 0013 // Commander's ground-speed/slip indicator
#define AID_P2_XPOINTER 0014 // Pilot's ground-speed/slip indicator
#define AID_P1_ADIBALL 0015 // Commander's Attitude/Direction indicator
#define AID_P2_ADIBALL 0016 // Pilot's Attitude/Direction indicator
// EVA Hatch
#define AID_EVAHANDLE_OPEN 0020
#define AID_EVAHANDLE_CLOSE 0021
#define AID_EVA_EGRESS 0022
// VC Active Areas (Panel 1)
#define AID_PANEL_1 ((id >= 0100) && (id <= 0124))
#define AID_SWITCH_P1_00 0100
#define AID_SWITCH_P1_01 0101
#define AID_SWITCH_P1_02 0102
#define AID_SWITCH_P1_03 0103 // Engine arm
#define AID_SWITCH_P1_04 0104
#define AID_SWITCH_P1_05 0105 // Throttle Control Mode
#define AID_SWITCH_P1_06 0106
#define AID_SWITCH_P1_07 0107 // CDR's ACA prop
#define AID_SWITCH_P1_08 0110 // Manual control select
#define AID_SWITCH_P1_09 0111
#define AID_SWITCH_P1_10 0112
#define AID_SWITCH_P1_11 0113 // Ascent He REG 1
#define AID_SWITCH_P1_12 0114 // Descent He REG 1
#define AID_SWITCH_P1_13 0115 // Ascent He REG 2
#define AID_SWITCH_P1_14 0116 // Descent He REG 2
#define AID_SWITCH_P1_15 0117
#define AID_SWITCH_P1_16 0120
#define AID_SWITCH_P1_17 0121 // Guidance control
#define AID_SWITCH_P1_18 0122 // Altimeter mode select
#define AID_SWITCH_P1_19 0123
#define AID_DIAL_P1_00 0124
#define AID_BTN_P1_ABORT 0007 // Docking latch release button
#define AID_BTN_P1_ABORTSTAGE 0010 // Abort Stage button
// VC Active Areas (Panel 2)
#define AID_PANEL_2 ((id >= 0200) && (id <= 0226))
#define AID_SWITCH_P2_00 0201 // RCS "A" propellant shut off valve
#define AID_SWITCH_P2_01 0202 // RCS "A" quad-1
#define AID_SWITCH_P2_02 0203 // RCS "A" quad-2
#define AID_SWITCH_P2_03 0204 // RCS A/B cross-feed valve
#define AID_SWITCH_P2_04 0205 // RCS "A" oxidizer shut off valve
#define AID_SWITCH_P2_05 0206 // RCS "A" quad-4
#define AID_SWITCH_P2_06 0207 // RCS "A" quad-3
#define AID_SWITCH_P2_07 0210 // RCS "A" ascent tank cross-feed valve
#define AID_SWITCH_P2_08 0211 // RCS "B" propellant shut off valve
#define AID_SWITCH_P2_09 0212 // RCS "B" quad-1
#define AID_SWITCH_P2_10 0213 // RCS "B" quad-2
#define AID_SWITCH_P2_11 0214 // RCS "B" oxidizer shut off valve
#define AID_SWITCH_P2_12 0215 // RCS "B" quad-4
#define AID_SWITCH_P2_13 0216 // RCS "B" quad-3
#define AID_SWITCH_P2_14 0217 // RCS "B" ascent tank cross-feed valve
#define AID_SWITCH_P2_15 0220 // LMP's ACA prop
#define AID_SWITCH_P2_16 0221 // ADI Rate Scale
#define AID_SWITCH_P2_17 0222
#define AID_DIAL_P2_00 0223
#define AID_DIAL_P2_01 0224
#define AID_DIAL_P2_02 0225
#define AID_DIAL_P2_03 0226
// VC Active Areas (Panel 3)
#define AID_PANEL_3 ((id >= 0300) && (id <= 0337))
#define AID_SWITCH_P3_01 0301 // Engine gimbal
#define AID_SWITCH_P3_02 0302 // Command overide
#define AID_SWITCH_P3_03 0303
#define AID_SWITCH_P3_04 0304
#define AID_SWITCH_P3_05 0305
#define AID_SWITCH_P3_06 0306 // Dead band select
#define AID_SWITCH_P3_07 0307 // Pitch control mode
#define AID_SWITCH_P3_09 0310
#define AID_SWITCH_P3_10 0311 // Roll control mode
#define AID_SWITCH_P3_12 0312 // Event timer start
#define AID_SWITCH_P3_13 0313 // Yaw control mode
#define AID_SWITCH_P3_14 0314
#define AID_SWITCH_P3_15 0315 // Event timer mode
#define AID_SWITCH_P3_16 0316
#define AID_SWITCH_P3_17 0317 // Quad 1 heater
#define AID_SWITCH_P3_18 0320 // Quad 2 heater
#define AID_SWITCH_P3_19 0321 // Event timer slew (min)
#define AID_SWITCH_P3_20 0322 // Quad 4 heater
#define AID_SWITCH_P3_21 0323 // Quad 3 heater
#define AID_SWITCH_P3_22 0324 // Event timer slew (sec)
#define AID_SWITCH_P3_23 0325
#define AID_SWITCH_P3_24 0326
#define AID_SWITCH_P3_25 0327
#define AID_DIAL_P3_00 0332
#define AID_DIAL_P3_01 0333
#define AID_DIAL_P3_02 0334 // Attitude control mode
#define AID_DIAL_P3_03 0335
#define AID_DIAL_P3_04 0336
#define AID_DIAL_P3_05 0337
// VC Active Areas (Panel 4)
#define AID_PANEL_4 ((id >= 0400) && (id <= 0404))
#define AID_SWITCH_P4_00 0401 // CDR's RCS vernier
#define AID_SWITCH_P4_01 0402 // CDR's RCS mode select
#define AID_SWITCH_P4_02 0403 // LMP's RCS vernier
#define AID_SWITCH_P4_03 0404 // LMP's RCS mode select
#define AID_MFD_P4_LBUTTONS 0411 // MFD soft-keys (Left side)
#define AID_MFD_P4_RBUTTONS 0412 // MFD soft-keys (Right side)
#define AID_MFD_P4_PWR 0413 // MFD 'Power' button
#define AID_MFD_P4_SEL 0414 // MFD 'Select' button
#define AID_MFD_P4_MNU 0415 // MFD 'Menu' button
// VC Active Areas (Panel 5)
#define AID_PANEL_5 ((id >= 0500) && (id <= 0516))
#define AID_SWITCH_P5_00 0501 // Mission timer mode
#define AID_SWITCH_P5_01 0502
#define AID_SWITCH_P5_02 0503 // Mission timer slew (hrs)
#define AID_SWITCH_P5_03 0504
#define AID_SWITCH_P5_04 0505 // Mission timer slew (min)
#define AID_SWITCH_P5_05 0506
#define AID_SWITCH_P5_06 0507 // Mission timer slew (sec)
#define AID_SWITCH_P5_07 0510
#define AID_BTN_P5_XTRANS 0511 // Ullage burn
#define AID_BTN_P5_START 0512 // Start engine
#define AID_BTN_P5_STOP 0513 // Kill thrust
#define AID_DIAL_P5_00 0514 // Floodlights
#define AID_DIAL_P5_01 0515 // Panel lights
#define AID_DIAL_P5_02 0516 // Displays
// VC Active Areas (Panel 6)
#define AID_PANEL_6 ((id >= 0600) && (id <= 0626))
#define AID_SWITCH_P6_00 0600 // Gyro 1
#define AID_SWITCH_P6_01 0601 // Gyro 1
#define AID_SWITCH_P6_02 0602 // Gyro 2
#define AID_SWITCH_P6_03 0603 // Gyro 2
#define AID_SWITCH_P6_04 0604 // Gyro 1
#define AID_SWITCH_P6_05 0605 // Gyro 1
#define AID_SWITCH_P6_06 0606 // Gyro 2
#define AID_SWITCH_P6_07 0607 // Gyro 2
#define AID_SWITCH_P6_08 0610 // Gyro 1
#define AID_SWITCH_P6_09 0611 // Gyro 1
#define AID_SWITCH_P6_10 0612 // Gyro 2
#define AID_SWITCH_P6_11 0613 // Gyro 2
#define AID_DIAL_P6_00 0623 // Gyro 1, Ref Frame select
#define AID_DIAL_P6_01 0624 // Gyro 2, Ref Frame select
#define AID_DIAL_P6_02 0625 // Gyro 1, Target mode select
#define AID_DIAL_P6_03 0626 // Gyro 2, Target mode select
// Projection mode
// Primary Axis
// Set/Clear offset
// Nav Channel select
// VC Active Areas (Panel 8)
#define AID_PANEL_8 ((id >= 1000) && (id <= 1023))
#define AID_SWITCH_P8_00 1001
#define AID_SWITCH_P8_01 1002
#define AID_SWITCH_P8_02 1003
#define AID_SWITCH_P8_03 1004
#define AID_SWITCH_P8_04 1005
#define AID_SWITCH_P8_05 1006
#define AID_SWITCH_P8_06 1007
#define AID_SWITCH_P8_07 1008
#define AID_SWITCH_P8_08 1009
#define AID_SWITCH_P8_09 1010
#define AID_SWITCH_P8_10 1011
#define AID_SWITCH_P8_11 1012
#define AID_SWITCH_P8_12 1013
#define AID_SWITCH_P8_13 1014
#define AID_SWITCH_P8_14 1015
#define AID_SWITCH_P8_15 1016
#define AID_SWITCH_P8_16 1017
#define AID_SWITCH_P8_17 1018
#define AID_SWITCH_P8_18 1019
#define AID_SWITCH_P8_19 1020
#define AID_SWITCH_P8_20 1021
#define AID_SWITCH_P8_21 1022
#define AID_SWITCH_P8_22 1023
// VC Active Areas (Panel 12)
#define AID_PANEL_12 ((id >= 1200) && (id <= 1226))
#define AID_SWITCH_P12_00 1200
#define AID_SWITCH_P12_01 1201
#define AID_SWITCH_P12_02 1202
#define AID_SWITCH_P12_03 1203
#define AID_SWITCH_P12_04 1204
#define AID_SWITCH_P12_05 1205
#define AID_SWITCH_P12_06 1206
#define AID_SWITCH_P12_07 1207
#define AID_SWITCH_P12_08 1208
#define AID_SWITCH_P12_09 1209
#define AID_SWITCH_P12_10 1210
#define AID_SWITCH_P12_11 1211
#define AID_SWITCH_P12_12 1212
#define AID_SWITCH_P12_13 1213
#define AID_SWITCH_P12_14 1214
#define AID_SWITCH_P12_15 1215
#define AID_SWITCH_P12_16 1216
#define AID_SWITCH_P12_17 1217
#define AID_SWITCH_P12_18 1218
#define AID_SWITCH_P12_19 1219
#define AID_SWITCH_P12_20 1220
#define AID_SWITCH_P12_21 1221
#define AID_SWITCH_P12_22 1222
#define AID_DIAL_P12_00 1223
#define AID_DIAL_P12_01 1224
#define AID_DIAL_P12_02 1225
#define AID_DIAL_P12_03 1226
// VC Active Areas (Panel 14)
#define AID_PANEL_14 ((id >= 1400) && (id <= 1416))
#define AID_SWITCH_P14_00 1400
#define AID_SWITCH_P14_01 1401
#define AID_SWITCH_P14_02 1402
#define AID_SWITCH_P14_03 1403
#define AID_SWITCH_P14_04 1404
#define AID_SWITCH_P14_05 1405
#define AID_SWITCH_P14_06 1406
#define AID_SWITCH_P14_07 1407
#define AID_SWITCH_P14_08 1408
#define AID_SWITCH_P14_09 1409
#define AID_SWITCH_P14_10 1410
#define AID_SWITCH_P14_11 1411
#define AID_SWITCH_P14_12 1412
#define AID_SWITCH_P14_13 1413
#define AID_SWITCH_P14_14 1414
#define AID_SWITCH_P14_15 1415
#define AID_DIAL_P14_00 1416
// ==============================================================
// VC Constants
// ==============================================================
const double P1_TILT = 8*RAD;
const double P2_TILT = 8*RAD;
const double P3_TILT = 35*RAD;
const double P4_TILT = 45*RAD;
const double P6_TILT = 10*RAD;
const double P12_TILT = 20*RAD;
const double P14_TILT = 25*RAD;
// Number of switches on each panel
const int P1_NSWITCH = 20;
const int P2_NSWITCH = 18;
const int P3_NSWITCH = 23;
const int P4_NSWITCH = 4;
const int P5_NSWITCH = 8;
const int P6_NSWITCH = 12;
const int P8_NSWITCH = 22;
const int P12_NSWITCH = 22;
const int P14_NSWITCH = 16;
// Number of dials/thumbwheels
const int P1_NDIAL = 1;
const int P2_NDIAL = 4;
const int P3_NDIAL = 6;
const int P4_NDIAL = 0;
const int P5_NDIAL = 1;
const int P6_NDIAL = 4;
const int P8_NDIAL = 0;
const int P12_NDIAL = 4;
const int P14_NDIAL = 1;
// Dial rotation axises
const VECTOR3 P1_DIAL_AXIS = { 0.00, sin(P1_TILT),-cos(P1_TILT)};
const VECTOR3 P2_DIAL_AXIS = { 0.00, sin(P2_TILT),-cos(P2_TILT)};
const VECTOR3 P3_DIAL_AXIS = { 0.00, cos(P3_TILT),-cos(P3_TILT)};
const VECTOR3 P6_DIAL_AXIS = { 0.00, cos(P6_TILT),-sin(P6_TILT)};
const VECTOR3 P12_DIAL_AXIS = {-sin(P12_TILT), cos(P12_TILT), 0.00};
const VECTOR3 P14_DIAL_AXIS = { sin(P14_TILT), cos(P14_TILT), 0.00};
// ==============================================================
// Positions of active areas in VC mesh
// ==============================================================
const VECTOR3 ADI_BALL_POS[2] = { {-0.29190, 0.63346, 1.76486}, { 0.30211, 0.63346, 1.76486}};
const VECTOR3 VC_HUD_POS = {-0.59, 0.975,-1.12353};
const VECTOR3 MASTERCAUTION_POS[2] = { {-0.41025, 0.68624, 1.70677}, { 0.42073, 0.69283, 1.70771}};
const VECTOR3 UNDOCK_BTN_POS = {-0.09360, 0.53426, 1.68610};
const VECTOR3 ABORTSTAGE_BTN_POS = {-0.04435, 0.53426, 1.68610};
const VECTOR3 XTRANS_BTN_POS = {-0.61200, 0.02649, 1.46188};
const VECTOR3 START_BTN_POS = {-0.68256, 0.03258, 1.46172};
const VECTOR3 STOP_BTN_POS = {-0.68256, 0.04126, 1.51096};
const VECTOR3 MFD_POS = { 0.00000, 0.10972, 1.44827};
// MFD buttons (relative to MFD)
const VECTOR3 MFD_BUTTON_POS[11] = {
{-0.11331, 0.06884,-0.01354}, {-0.09703, 0.06884,-0.01354}, {-0.11331,-0.07099,-0.01354}, {-0.09703,-0.07099,-0.01354}, // Quadrilateral describing left side soft-keys
{ 0.09703, 0.06884,-0.01354}, { 0.11331, 0.06884,-0.01354}, { 0.09703,-0.07099,-0.01354}, { 0.11331,-0.07099,-0.01354}, // Quadrilateral describing right side soft-keys
{-0.07291,-0.09406,-0.01354}, { 0.05361,-0.09406,-0.01354}, { 0.07337,-0.09406,-0.01354} }; // Position of Power, Select, and Menu buttons
// Panel 1 Toggle-switchs
const VECTOR3 P1_TOGGLE_POS[P1_NSWITCH] = {
{-0.41112, 0.63679, 1.69711}, {-0.41112, 0.58858, 1.69117}, {-0.35903, 0.51596, 1.68097}, {-0.33970, 0.41121, 1.66625},
{-0.31091, 0.51596, 1.68097}, {-0.31091, 0.45853, 1.67290}, {-0.29446, 0.41121, 1.66625}, {-0.26431, 0.51596, 1.68097},
{-0.26431, 0.45853, 1.67290}, {-0.26039, 0.41121, 1.66625}, {-0.23584, 0.74792, 1.71273}, {-0.22377, 0.48943, 1.67724},
{-0.22377, 0.41121, 1.66625}, {-0.17579, 0.48943, 1.67724}, {-0.17579, 0.41121, 1.66625}, {-0.14838, 0.47650, 1.67542},
{-0.13043, 0.41994, 1.66747}, {-0.04043, 0.69083, 1.70554}, {-0.04043, 0.64232, 1.69873}, {-0.04043, 0.59233, 1.69170}};
// Panel 1 Dial
const VECTOR3 P1_DIAL_POS[P1_NDIAL] = { {-0.06803, 0.45938, 1.67554}};
// Panel 2 Toggle-switchs
const VECTOR3 P2_TOGGLE_POS[P2_NSWITCH] = {
{ 0.05041, 0.76698, 1.71625}, { 0.05041, 0.67718, 1.70362}, { 0.05041, 0.59878, 1.69261}, { 0.05098, 0.51056, 1.68021}, { 0.09446, 0.76698, 1.71625},
{ 0.09446, 0.67718, 1.70362}, { 0.09446, 0.59878, 1.69261}, { 0.12440, 0.51056, 1.68021}, { 0.13811, 0.76698, 1.71625}, { 0.13811, 0.67718, 1.70362},
{ 0.13811, 0.59878, 1.69261}, { 0.18217, 0.76698, 1.71625}, { 0.18217, 0.67718, 1.70362}, { 0.18217, 0.59878, 1.69261}, { 0.17825, 0.51056, 1.68021},
{ 0.17825, 0.45658, 1.67262}, { 0.42048, 0.64216, 1.69870}, { 0.42048, 0.58858, 1.69117}};
// Panel 2 Dials
const VECTOR3 P2_DIAL_POS[P2_NDIAL] = {
{ 0.05703, 0.45057, 1.67430}, { 0.24710, 0.49405, 1.68041}, { 0.24710, 0.42250, 1.67036}, { 0.36027, 0.45827, 1.67538}};
// Panel 3 Toggle-switchs
const VECTOR3 P3_TOGGLE_POS[P3_NSWITCH] = {
{-0.35652, 0.32535, 1.62434}, {-0.36395, 0.28302, 1.59471}, {-0.31776, 0.32535, 1.62434}, {-0.31776, 0.28302, 1.59471},
{-0.25709, 0.26603, 1.58281}, {-0.11335, 0.32744, 1.62581}, {-0.11335, 0.28496, 1.59606}, /*{-0.11335, 0.23648, 1.56212}, */
{-0.06036, 0.32744, 1.62581}, {-0.06036, 0.28496, 1.59606}, /*{-0.06036, 0.23648, 1.56212},*/ {-0.00681, 0.32744, 1.62581},
{-0.00681, 0.28496, 1.59606}, {-0.00681, 0.23648, 1.56212}, { 0.10519, 0.32744, 1.62581}, { 0.13944, 0.32744, 1.62581},
{ 0.13944, 0.28127, 1.59348}, { 0.13944, 0.23958, 1.56429}, { 0.17233, 0.32744, 1.62581}, { 0.17233, 0.28127, 1.59348},
{ 0.17233, 0.23958, 1.56429}, { 0.20522, 0.32744, 1.62581}, { 0.24006, 0.32744, 1.62581}, { 0.24006, 0.29890, 1.60583},
{ 0.35709, 0.23510, 1.56115}
};
// Panel 3 Dials
const VECTOR3 P3_DIAL_POS[P3_NDIAL] = {
{-0.33425, 0.23079, 1.56118}, {-0.19012, 0.24194, 1.56899}, {-0.08162, 0.23373, 1.56324}, { 0.06008, 0.24099, 1.56833},
{ 0.26664, 0.23420, 1.56357}, { 0.30563, 0.29777, 1.60808}
};
// Panel 4 Toggle-switchs
const VECTOR3 P4_TOGGLE_POS[P4_NSWITCH] = {
{-0.12900, 0.14776, 1.48380}, {-0.12900, 0.08487, 1.42090}, { 0.13500, 0.14776, 1.48380}, { 0.13500, 0.08487, 1.42090}
};
// Panel 5 Toggle-switchs
const VECTOR3 P5_TOGGLE_POS[P5_NSWITCH] = {
{-0.59670, 0.03450, 1.49293}, {-0.55200, 0.02374, 1.43190}, {-0.54173, 0.03450, 1.49293}, {-0.51697, 0.02374, 1.43190},
{-0.49969, 0.03450, 1.49293}, {-0.48194, 0.02374, 1.43190}, {-0.45762, 0.03450, 1.49293}, {-0.44691, 0.02374, 1.43190},
};
// Panel 6 Toggle-switchs
const VECTOR3 P6_TOGGLE_POS[P6_NSWITCH] = {
{ 0.64043, 0.03879, 1.51246}, { 0.64043, 0.03011, 1.46319}, { 0.64043, 0.02092, 1.41107}, { 0.64043, 0.01223, 1.36180},
{ 0.67543, 0.03879, 1.51246}, { 0.67543, 0.03011, 1.46319}, { 0.67543, 0.02092, 1.41107}, { 0.67543, 0.01223, 1.36180},
{ 0.71042, 0.03879, 1.51246}, { 0.71042, 0.03011, 1.46319}, { 0.71042, 0.02092, 1.41107}, { 0.71042, 0.01223, 1.36180},
};
// Panel 6 Dials
const VECTOR3 P6_DIAL_POS[P6_NDIAL] = {
{ 0.49704, 0.03177, 1.49183}, { 0.49704, 0.01389, 1.39044}, { 0.58025, 0.03177, 1.49183}, { 0.58025, 0.01389, 1.39044}
};
// Panel 8 Toggle-switchs
const VECTOR3 P8_TOGGLE_POS[P8_NSWITCH] = {
{-1.07517, 0.18985, 1.04111}, {-1.07517, 0.18985, 1.07512}, {-0.98428, 0.15676, 1.08001}, {-1.09473, 0.19697, 1.11613},
{-0.98428, 0.15676, 1.11001}, {-1.04353, 0.17833, 1.18348}, {-0.98996, 0.15883, 1.18348}, {-1.09335, 0.19646, 1.21348},
{-1.04353, 0.17833, 1.21348}, {-1.09335, 0.19646, 1.24348}, {-1.04353, 0.17833, 1.24348}, {-0.99655, 0.16123, 1.24348},
{-1.09335, 0.19646, 1.27348}, {-1.04353, 0.17833, 1.27348}, {-0.99655, 0.16123, 1.27348}, {-1.10953, 0.20235, 1.35700},
{-1.02496, 0.17157, 1.35700}, {-1.10953, 0.20235, 1.39700}, {-1.02496, 0.17157, 1.39700}, {-1.07194, 0.18867, 1.44199},
{-1.07194, 0.18867, 1.48199}, {-0.98159, 0.15579, 1.49572}
};
// Panel 12 Toggle-switchs
const VECTOR3 P12_TOGGLE_POS[P12_NSWITCH] = {
{ 1.01020, 0.07249, 1.51678}, { 1.08673, 0.10035, 1.49908}, { 1.12601, 0.11465, 1.45174}, { 1.04277, 0.08435, 1.45174},
{ 1.12601, 0.11465, 1.39949}, { 1.04277, 0.08435, 1.39949}, { 1.12734, 0.11513, 1.34949}, { 1.08975, 0.10145, 1.34949},
{ 1.10855, 0.10829, 1.30949}, { 1.10855, 0.10829, 1.26949}, { 1.05714, 0.08958, 1.26396}, { 1.10855, 0.10829, 1.22949},
{ 1.05714, 0.08958, 1.22396}, { 1.11352, 0.11010, 1.18210}, { 1.05714, 0.08958, 1.18927}, { 1.05714, 0.08958, 1.14927},
{ 1.11352, 0.11010, 1.13210}, { 1.05714, 0.08958, 1.12073}, { 1.11352, 0.11010, 1.09210}, { 1.05714, 0.08958, 1.08073},
{ 1.00075, 0.06906, 1.08073}, { 1.05714, 0.08958, 1.04375}
};
// Panel 12 Dials
const VECTOR3 P12_DIAL_POS[P12_NDIAL] = {
{ 1.01313, 0.07094, 1.02660}, { 1.01313, 0.07094, 0.95302}, { 1.10485, 0.10432, 0.88523}, { 1.02386, 0.07484, 0.88523}
};
// Panel 14 Toggle-switchs
const VECTOR3 P14_TOGGLE_POS[P14_NSWITCH] = {
{ 1.03621, 0.31420, 1.32009}, { 1.03621, 0.31420, 1.25009}, { 1.07247, 0.33111, 1.18009}, { 1.03621, 0.31420, 1.18009},
{ 1.07247, 0.33111, 1.15009}, { 1.07247, 0.33111, 1.11326}, { 1.03621, 0.31420, 1.11326}, { 1.07247, 0.33111, 1.08326},
{ 1.03621, 0.31420, 1.08326}, { 1.07247, 0.33111, 1.05326}, { 1.03621, 0.31420, 1.05326}, { 1.06281, 0.32661, 1.00857},
{ 1.06281, 0.32661, 0.96491}, { 1.06281, 0.32661, 0.92641}, { 1.06281, 0.32661, 0.88962}, { 1.06281, 0.32661, 0.83221}
};
// Panel 14 Dial
const VECTOR3 P14_DIAL_POS[P14_NDIAL] = {{ 1.08456, 0.33399, 1.25001}};
// ==============================================================
// Class declaration
// ==============================================================
class LM_COCKPIT
{
That is a list of every switch, display, and button in our cockpit. each with a unique index number and 3D position assigned to it.
Yes it's a lot of information, but defining it once in the header file allows us to access it at will and will make what comes next a lot easier. Lets start with something simple, making the door open.
Open our RegisterActiveAreas function and add the following lines...
Code:
// --------------------------------------------------------------
// Register VC active areas
// --------------------------------------------------------------
void LM_COCKPIT::RegisterActiveAreas (VECTOR3 ofs)
{
int i = 0;
[COLOR="Red"] // EVA hatch handle
oapiVCRegisterArea (AID_EVAHANDLE_OPEN, PANEL_REDRAW_NEVER, PANEL_MOUSE_DOWN);
oapiVCSetAreaClickmode_Spherical( AID_EVAHANDLE_OPEN, _V(-0.3356, -0.6232, 1.5988) + ofs, 0.08);
oapiVCRegisterArea (AID_EVAHANDLE_CLOSE, PANEL_REDRAW_NEVER, PANEL_MOUSE_DOWN);
oapiVCSetAreaClickmode_Spherical (AID_EVAHANDLE_CLOSE, _V( 0.3300, -0.4888, 0.9368) + ofs, 0.08);[/COLOR]
What we are doing here is creating two active areas. thier postions correlate to the positions of the EVA hatch's door handle when the door is open and when the door is closed. Let's break them down.
"oapiVCRegisterArea (AID_EVAHANDLE_OPEN, PANEL_REDRAW_NEVER, PANEL_MOUSE_DOWN);
"
This line is the initial declaration of the active area. "AID_EVAHANDLE_OPEN" is the index number as defined in our header file, "PANEL_REDRAW_NEVER" indicates that there are no "redraw events" associated with the active area. Redraw events are how the VC updates things like gauges and other displays. "PANEL_MOUSE_DOWN" means that the active area is activated when someone clicks on it (mouse button is down).
"oapiVCSetAreaClickmode_Spherical (AID_EVAHANDLE_CLOSE, _V( 0.3300,-0.4888, 0.9368) + ofs, 0.08);"
This line states what kind of active area we are dealing with and it's posittion within the cockpit. In this case the active area is a spherical zone 0.08 units in diameter (8 cm) at the position indicated.
Now that we have an active area it's time to assign a function to it.
In the vessel class itself parsing of cockpit inputs is handled by "clbkVCMouseEvent" to serve this purpose you will see that I have placed a function called "MouseEvent" in our cockpit control class.
In it I have placed the following lines...
Code:
// --------------------------------------------------------------
// Respond to user inputs
// --------------------------------------------------------------
bool LM_COCKPIT::MouseEvent (int id, int event, VECTOR3 &p)
{
[COLOR="Red"] switch (id)
{
// EVA hatch handle
case AID_EVAHANDLE_OPEN:
if (v->HatchStatus == CLOSED) v->HatchStatus = OPENING; // If hatch is closed open hatch
return true;
case AID_EVAHANDLE_CLOSE:
if (v->HatchStatus == OPEN) v->HatchStatus = CLOSING; // If hatch is open close hatch
return true;
}[/COLOR]
return false;
When the user clicks on an active area Orbiter automatically passes the index number of the area to the mouse event parser, the "id" variable in the above code. The parser then compares that id number to it's list of possibles contained in the "switch (id)" function. If it finds a match it performs the assigned function and returns true, otherwise it returns false.
In this case the functions and their purpose should be readily apparent.
NOTE: v-> is a interface that allows us to manipulate data/call functions from our parent vessel as described in part 13.
Now that we have the some active areas registered and some lines for our parser to chew on we need to add them to our simulation. Our cockpit is not actually a vessel, planet, mfd, or somesuch and as such Orbiter will ignore it unless we specifically tell it otherwise.
To do this we need to go back to our lunar module's code and add calls for the cockpit's functions.
In ClbkLoadVC add a call to register our active areas.
Code:
// --------------------------------------------------------------
// Load virtual cockpit mode
// --------------------------------------------------------------
bool LM::clbkLoadVC (int id)
{
// Check CG offset
VECTOR3 ofs;
if (CoG_shifted) ofs = _V( 0, 0, 0);
else ofs = LM_ASC_OFFSET;
// Register MFD
static VCMFDSPEC Cmd_MFD = {mesh_Cockpit, VC_GRP_MFD_Cmd}; // Surface on which to display MFD. (Mesh, Mesh Group)
oapiVCRegisterMFD (0, &Cmd_MFD); // Register MFD in orbiter's interface [registry # and VCMFDSPEC]. (registry numbers start at 0 and count up)
[COLOR="red"] // Register active areas
vc->RegisterActiveAreas (ofs);
[/COLOR]
Then to handle our mouse events overload "clbkVCMouseEvent" and add the following line.
Code:
// --------------------------------------------------------------
// Respond to virtual cockpit mouse events
// --------------------------------------------------------------
bool LM::clbkVCMouseEvent (int id, int event, VECTOR3 &p)
{
[COLOR="red"] return vc->MouseEvent (id, event, p); // Pass user inputs to cockpit control class[/COLOR]
} // End "LM::clbkLoadVC"
The active areas should now be registered in orbiter and user inputs will be passed to the cockpit control class to be parsed.
Compile and test your handy work. clicking on the hatch handle in the VC should now cause the hatch to open or close.
NEXT UP: Animated Switches.