using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Orbiter.Interfaces;
using Orbiter.Wrapper;
using MeshGroupRotation=Orbiter.Interfaces.MeshGroupRotation;
using MeshGroupTranslation=Orbiter.Interfaces.MeshGroupTranslation;
using Vessel=Orbiter.Interfaces.Vessel;
using Vessel2=Orbiter.Interfaces.Vessel2;

namespace Orbiter.StockVessels
{
    public class DeltaGlider : Vessel2
    {
        private class GDIParams
        {
            IntPtr/*HINSTANCE*/ hDLL;
            IntPtr[]/*HFONT*/ font=new IntPtr[2];
            uint[] col=new uint[4];
            IntPtr[]/*HBRUSH*/ brush=new IntPtr[4];
            IntPtr[]/*HPEN*/ pen=new IntPtr[2];
        }
        // Some mesh groups referenced in the code
        private enum MeshGroups
        {
            VC_HUDMODE       =   0,
            VC_HBALANCECNT   =  18,
            VC_SCRAMGIMBALCNT=  19,
            VC_PGIMBALCNT    =  20,
            VC_YGIMBALCNT    =  21,
            VC_NAVMODE       =  59,
            VC_LMFDDISP      = 109,
            VC_RMFDDISP      = 110,
            VC_STATUSIND     = 118,
            VC_HORIZON       = 120,
            VC_HUDDISP       = 136,
        }

        // Panel area identifiers:
        private enum AreaId
        {
            // Panel 0
            PROPELLANTSTATUS = 0,
            ENGINEMAIN = 2,
            ENGINEHOVER = 3,
            ENGINESCRAM = 4,
            ATTITUDEMODE = 5,
            ADCTRLMODE = 6,
            NAVMODE = 7,
            HUDMODE = 8,
            AOAINSTR = 9,
            SLIPINSTR = 10,
            LOADINSTR = 11,
            HORIZON = 13,
            MFD1_BBUTTONS = 14,
            MFD1_LBUTTONS = 15,
            MFD1_RBUTTONS = 16,
            MFD2_BBUTTONS = 17,
            MFD2_LBUTTONS = 18,
            MFD2_RBUTTONS = 19,
            PGIMBALMAIN = 22,
            PGIMBALMAINMODE = 23,
            YGIMBALMAIN = 24,
            YGIMBALMAINMODE = 25,
            GIMBALSCRAM = 26,
            GIMBALSCRAMMODE = 27,
            ELEVATORTRIM = 28,
            PGIMBALMAINDISP = 29,
            YGIMBALMAINDISP = 30,
            GIMBALSCRAMDISP = 31,
            MAINDISP1 = 32,
            MAINDISP2 = 33,
            MAINDISP3 = 34,
            MAINDISP4 = 35,
            SCRAMDISP2 = 36,
            SCRAMDISP3 = 37,
            MAINPROP = 38,
            MAINPROPMASS = 39,
            RCSPROP = 40,
            RCSPROPMASS = 41,
            SCRAMPROP = 42,
            SCRAMPROPMASS = 43,
            HOVERBALANCE = 44,
            HBALANCEMODE = 45,
            HBALANCEDISP = 46,
            RADIATORSWITCH = 47,
            RETRODOORSWITCH = 48,
            HATCHSWITCH = 49,
            LADDERSWITCH = 50,
            MWS = 51,

            // Panel 1
            OUTERAIRLOCKBUTTON = 100,
            INNERAIRLOCKBUTTON = 101,
            NAVLIGHTBUTTON = 102,
            BEACONBUTTON = 103,
            STROBEBUTTON = 104,
            VPITCH = 105,
            VBANK = 106,
            VYAW = 107,
            APITCH = 108,
            ABANK = 109,
            AYAW = 110,
            MPITCH = 111,
            MBANK = 112,
            MYAW = 113,
            SCRAMTEMPDISP = 114,

            // Panel 2
            WBRAKE_BOTH = 200,
            WBRAKE_LEFT = 201,
            WBRAKE_RIGHT = 202,
            GEARLEVER = 203,
            NOSECONELEVER = 204,
            GEARINDICATOR = 205,
            NOSECONEINDICATOR = 206,
            DOCKRELEASE = 207,

            // Virtual cockpit-specific area identifiers:
            MFD1_PWR = 1024,
            MFD1_SEL = 1025,
            MFD1_MNU = 1026,
            MFD2_PWR = 1027,
            MFD2_SEL = 1028,
            MFD2_MNU = 1029,
            HUDBUTTON1 = 1030,
            HUDBUTTON2 = 1031,
            HUDBUTTON3 = 1032,
            HUDBUTTON4 = 1033,
            HUDCOLOUR = 1034,
            HUDINCINTENS = 1035,
            HUDDECINTENS = 1036,
            NAVBUTTON1 = 1037,
            NAVBUTTON2 = 1038,
            NAVBUTTON3 = 1039,
            NAVBUTTON4 = 1040,
            NAVBUTTON5 = 1041,
            NAVBUTTON6 = 1042,
            RADIATOREX = 1043,
            RADIATORIN = 1044,
            HATCHOPEN = 1045,
            HATCHCLOSE = 1046,
            LADDEREX = 1047,
            LADDERIN = 1048,
            RCOVEROPEN = 1049,
            RCOVERCLOSE = 1050,
            ILOCKOPEN = 1051,
            ILOCKCLOSE = 1052,
            OLOCKOPEN = 1053,
            OLOCKCLOSE = 1054,
            NCONEOPEN = 1055,
            NCONECLOSE = 1056,
            GEARDOWN = 1057,
            GEARUP = 1058,
        }

        private enum DoorStatus
        {
            CLOSED,
            OPEN,
            CLOSING,
            OPENING
        }

        private enum CameraPositions
        {
            GENERIC,
            PANELMAIN,
            PANELUP,
            PANELDN,
            VCPILOT,
            VCPSNGR1,
            VCPSNGR2,
            VCPSNGR3,
            VCPSNGR4
        }
        
        private class PrpDisp
        {
            // propellant status display parameters
		    public int dsp_main;
            public int dsp_rcs;
		    public string lvl_main;
		    public string lvl_rcs;
		    public string mass_main;
            public string mass_rcs;
		    public string flow_main;
            public string flow_rcs;
	    }

	    private class EngDisp
	    {
	        // engine status display parameters
		    public int[] bar=new int[2];
		    public string[] dsp=new string[6];
	    }

	    private class RngDisp
	    {
		    public string[] dsp=new string[2];
	    }
        
        // ==============================================================
        // Some vessel class caps
        // Where an entry consists of two values, the first refers to the
        // "easy", the second to the "complex" flight model.
        // ==============================================================

        private const double EMPTY_MASS    = 11000.0;  // standard configuration
        private const double EMPTY_MASS_SC = 13000.0;  // ramjet configuration
        // DG mass w/o fuel

        private const double PSNGR_MASS    =     85.0;
        // mass per passenger (including life support system)

        private const double TANK1_CAPACITY = 10400.0;
        private const double TANK2_CAPACITY =  2500.0;
        // Main fuel tank capacities [kg] (can be split between rocket
        // fuel and scramjet fuel)

        private const double RCS_FUEL_CAPACITY = 600.0;
        // Max fuel capacity: RCS tank [kg]

        private static readonly double[] MAX_MAIN_THRUST = new double[]{2.0e5, 1.6e5};
        // Main engine max vacuum thrust [N] per engine. (x2 for total)

        private const double MAX_RETRO_THRUST = 3.4e4;
        // Retro engine max vacuum thrust [N] per engine. (x2 for total)

        private static readonly double[] MAX_HOVER_THRUST = new double[]{1.4e5, 1.1e5};
        // Hover engine max vacuum thrust [N] (x2 for total)

        private const double MAX_RCS_THRUST = 2.5e3;
        // Attitude control system max thrust [N] per engine.

        private const double ISP = 4e4;
        // Vacuum Isp (fuel-specific impulse) for all thrusters [m/s]

        private const double GEAR_OPERATING_SPEED = 0.15;
        // Opening/closing speed of landing gear (1/sec)
        // => gear cycle ~ 6.7 sec

        private const double NOSE_OPERATING_SPEED = 0.05;
        // Opening/closing speed of nose cone docking mechanism (1/sec)
        // => cycle = 20 sec

        private const double AIRLOCK_OPERATING_SPEED = 0.1;
        // Opening/closing speed of outer airlock (1/sec)
        // => cycle = 10 sec

        private const double RADIATOR_OPERATING_SPEED = 0.03125;
        // Deployment speed of radiator (1/sec)
        // => cycle = 32 sec

        private const double AIRBRAKE_OPERATING_SPEED = 0.3;
        // Deployment speed of airbrakes
        // => cycle = 3.3 sec

        private const double LADDER_OPERATING_SPEED = 0.1;
        // Deployment speed of escape ladder

        private const double HATCH_OPERATING_SPEED = 0.15;
        // Opening/closing speed of top hatch

        private const double RCOVER_OPERATING_SPEED = 0.3;
        // Retro cover opening/closing speed

        // ========= Main engine parameters ============

        private static readonly double MAIN_PGIMBAL_RANGE = Math.Tan(1.0*Constants.Radiant);
        private const double MAIN_YGIMBAL_RANGE = 1.0/7.7;
        // main engine pitch and yaw gimbal range (tan)

        private const double MAIN_PGIMBAL_SPEED = 0.007;
        private const double MAIN_YGIMBAL_SPEED = 0.035;
        // operating speed of main engine pitch and yaw gimbals

        private const double MAX_HOVER_IMBALANCE = 4e3;
        // max thrust imbalance between front and aft hover engines [N]

        private const double HOVER_BALANCE_SPEED = 2e3;
        // operating speed of hover balance shift control

        // ========== Scramjet parameters ==============

        private const double SCRAM_FUEL_CAPACITY = 5000.0;
        // Max. scramjet fuel capacity [kg]

        private static readonly double[] SCRAM_TEMAX = new double[]{3500.0, 3200.0};
        // Max. scramjet exhaust temperature [K]

        private static readonly double[] SCRAM_FHV = new double[]{3.5e8, 2.0e8};
        // Scramjet fuel heating value [J/kg]: Amount of heat energy
        // obtained from burning 1kg of propellant

        private static readonly double[] SCRAM_MAX_DMF = new double[]{2.0,3.0};
        // Max. scramjet fuel flow rate [kg/s]

        private const double SCRAM_INTAKE_AREA = 1.0;
        // Scramjet intake cross section (per engine) [m^2]

        private const double SCRAM_DEFAULT_DIR = 9.0 * Constants.Radiant;
        // Default scramjet thrust angle (rad)

        private const double SCRAM_GIMBAL_RANGE = 5.0 * Constants.Radiant;
        // Scramjet gimbal range (rad)

        private const double SCRAM_GIMBAL_SPEED = SCRAM_GIMBAL_RANGE / 3.0;
        // Operating speed of scramjet pitch gimbals (rad/s)

        // ============ Damage parameters ==============

        private const double WINGLOAD_MAX = 16e3;
        private const double WINGLOAD_MIN = -10e3;
        // Max. allowed positive and negative wing load [N/m^2]

        private const double DYNP_MAX = 300e3;
        // Max. allowed dynamic pressure [Pa]

        // =============================================

        private const int nsurf = 12; // number of bitmap handles
        
        private double alt;       // altitude
        private double range;     // glide range
	    private double aoa_ind;   // angle of AOA needle (NOT AOA!)
	    private double slip_ind;  // angle of slip indicator needle
	    private double load_ind;  // angle of load indicator needle
	    private int[] mpgimbalidx=new int[2];// main pitch gimbal slider positions and button states
        private int[] mpswitch=new int[2];// main pitch gimbal slider positions and button states
        private int mpmode; // main pitch gimbal slider positions and button states
	    private int[] mygimbalidx=new int[2];// main yaw gimbal slider positions and button states
        private int[] myswitch=new int[2];// main yaw gimbal slider positions and button states
        private int mymode; // main yaw gimbal slider positions and button states
	    private int[] scgimbalidx=new int[2]; // scramjet gimbal slider positions and button states
        private int[] sgswitch=new int[2]; // scramjet gimbal slider positions and button states
        private int spmode; // scramjet gimbal slider positions and button states
	    private int hbalanceidx, hbswitch, hbmode;       // hover balance slider position
	    private bool[] psngr=new bool[4];                           // passengers?
	    private bool bDamageEnabled;                     // damage/failure testing?

	    // parameters for failure modelling
	    private double lwingstatus, rwingstatus;
	    private int hatchfail;
	    private bool[] aileronfail=new bool[4];
        
        private DoorStatus nose_status;
        private DoorStatus ladder_status;
        private DoorStatus gear_status;
        private DoorStatus rcover_status;
        private DoorStatus olock_status;
        private DoorStatus ilock_status;
        private DoorStatus hatch_status;
        private DoorStatus radiator_status;
        private DoorStatus brake_status;
        
        private DoublePointer nose_proc;     // logical status
        private double ladder_proc;     // logical status
        private DoublePointer gear_proc;     // logical status
        private DoublePointer rcover_proc;     // logical status
        private double olock_proc;     // logical status
        private double ilock_proc;     // logical status
        private double hatch_proc;     // logical status
        private DoublePointer radiator_proc;     // logical status
        private DoublePointer brake_proc;     // logical status
	    private uint anim_gear;         // handle for landing gear animation
	    private uint anim_rcover;       // handle for retro cover animation
	    private uint anim_nose;         // handle for nose cone animation
	    private uint anim_ladder;       // handle for front escape ladder animation
	    private uint anim_olock;        // handle for outer airlock animation
	    private uint anim_ilock;        // handle for inner airlock animation
	    private uint anim_hatch;        // handle for top hatch animation
	    private uint anim_radiator;     // handle for radiator animation
	    private uint anim_rudder;       // handle for rudder animation
	    private uint anim_elevator;     // handle for elevator animation
	    private uint anim_elevatortrim; // handle for elevator trim animation
	    private uint anim_laileron;     // handle for left aileron animation
	    private uint anim_raileron;     // handle for right aileron animation
	    private uint anim_brake;        // handle for airbrake animation
	    private uint[] anim_mainthrottle=new uint[2];  // VC main/retro throttle levers (left and right)
	    private uint anim_hoverthrottle;    // VC hover throttle
	    private uint[] anim_scramthrottle=new uint[2]; // VC scram throttle levers (left and right)
	    private uint anim_gearlever;        // VC gear lever
	    private uint anim_nconelever;       // VC nose cone lever
	    private uint[] anim_pmaingimbal=new uint[2];   // VC main engine pitch gimbal switch (left and right engine)
	    private uint[] anim_ymaingimbal=new uint[2];   // VC main engine yaw gimbal switch (left and right engine)
	    private uint[] anim_scramgimbal=new uint[2];   // VC scram engine pitch gimbal switch (left and right engine)
	    private uint anim_hbalance;         // VC hover balance switch
	    private uint anim_hudintens;        // VC HUD intensity switch
	    private uint anim_rcsdial;          // VC RCS dial animation
	    private uint anim_afdial;           // VC AF dial animation
	    private uint anim_olockswitch;      // VC outer airlock switch animation
	    private uint anim_ilockswitch;      // VC inner airlock switch animation
	    private uint anim_retroswitch;      // VC retro cover switch animation
	    private uint anim_ladderswitch;     // VC ladder switch animation
	    private uint anim_hatchswitch;      // VC hatch switch animation
	    private uint anim_radiatorswitch;   // VC radiator switch animation

	    private IntPtr[] /*SURFHANDLE*/ srf=new IntPtr[nsurf];          // handles for panel bitmaps
	    private IntPtr /*SURFHANDLE*/ insignia_tex;        // vessel-specific fuselage markings
	    private IntPtr /*MESHHANDLE*/ exmesh, exmesh_tpl;  // local external mesh and global template
	    private IntPtr /*MESHHANDLE*/ vcmesh, vcmesh_tpl;  // local VC mesh and global template
	    private IntPtr /*THGROUP_HANDLE*/ thg_main;
	    private IntPtr /*THGROUP_HANDLE*/ thg_retro;
	    private IntPtr /*THGROUP_HANDLE*/ thg_hover;

        private CameraPositions campos;
        
        public BeaconLightSpecification[] beacon=new BeaconLightSpecification[7];                   // light beacon definitions
        
        private Ramjet scramjet;                            // scramjet module (NULL = none)
	    private bool bMWSActive;                     // master warning flags
        private bool bMWSOn;                     // master warning flags
	    private int modelidx;                                // flight model index
	    private int tankconfig;                              // 0=rocket fuel only, 1=scramjet fuel only, 2=both
	    private double max_rocketfuel;        // max capacity for rocket and scramjet fuel
        private double max_scramfuel;        // max capacity for rocket and scramjet fuel
	    private IntPtr /*VISHANDLE*/ visual;                            // handle to DG visual representation
	    private IntPtr[] /*SURFHANDLE*/ skin=new IntPtr[3];                          // custom skin textures, if applicable
	    private string skinpath;                           // skin directory, if applicable
	    private IntPtr /*PROPELLANT_HANDLE*/ ph_main;
        private IntPtr /*PROPELLANT_HANDLE*/ ph_rcs;
        private IntPtr /*PROPELLANT_HANDLE*/ ph_scram; // propellant resource handles
	    private IntPtr[] /*THRUSTER_HANDLE*/ th_main=new IntPtr[2];                  // main engine handles
	    private IntPtr[] /*THRUSTER_HANDLE*/ th_retro=new IntPtr[2];                 // retro engine handles
	    private IntPtr[] /*THRUSTER_HANDLE*/ th_hover=new IntPtr[2];                 // hover engine handles
	    private IntPtr[] /*THRUSTER_HANDLE*/ th_scram=new IntPtr[2];                 // scramjet handles
	    private IntPtr /*AIRFOILHANDLE*/ hwing;                         // airfoil handle for wings
	    private IntPtr /*CTRLSURFHANDLE*/ hlaileron, hraileron;         // control surface handles
	    private IntPtr /*PSTREAM_HANDLE*/ hatch_vent;
	    private double hatch_vent_t;
	    private bool dockreleasedown;

	    private uint[] engsliderpos=new uint[5];    // throttle settings for main,hover,scram engines
	    private uint elevtrimpos;        // elevator trim indicator position
        private DoublePointer[] scram_intensity = new DoublePointer[2];
	    private double[] scram_max=new double[2];
	    private uint[] wbrake_pos=new uint[2];
	    private int[] mainflowidx=new int[2];
        private int[] retroflowidx=new int[2];
        private int hoverflowidx;
        private int[] scflowidx=new int[2];
	    private int mainTSFCidx;
        private int[] scTSFCidx=new int[2];
	    private int[] mainpropidx=new int[2];
        private int[] rcspropidx=new int[2];
        private int[] scrampropidx=new int[2];
	    private int mainpropmass, rcspropmass, scrampropmass;
	    private int[][] rotidx=new int[3][];
        
        private PrpDisp p_prpdisp;
	    private EngDisp p_engdisp;
	    private RngDisp p_rngdisp;
        
        private const Vessel2Callback callbackSetting = Vessel2Callback.SetClassCaps |
                                                        Vessel2Callback.LoadStateEx |
                                                        Vessel2Callback.SaveState |
                                                        Vessel2Callback.PostCreation |
                                                        Vessel2Callback.VisualCreated |
                                                        Vessel2Callback.VisualDestroyed |
                                                        Vessel2Callback.PostStep |
                                                        Vessel2Callback.PlaybackEvent |
                                                        Vessel2Callback.DrawHUD |
                                                        Vessel2Callback.RCSMode |
                                                        Vessel2Callback.ADCtrlMode |
                                                        Vessel2Callback.HUDMode |
                                                        Vessel2Callback.MFDMode |
                                                        Vessel2Callback.NavMode |
                                                        Vessel2Callback.ConsumeDirectKey |
                                                        Vessel2Callback.ConsumeBufferedKey |
                                                        Vessel2Callback.LoadGenericCockpit |
                                                        Vessel2Callback.LoadPanel |
                                                        Vessel2Callback.PanelMouseEvent |
                                                        Vessel2Callback.PanelRedrawEvent |
                                                        Vessel2Callback.LoadVC |
                                                        Vessel2Callback.VCMouseEvent |
                                                        Vessel2Callback.VCRedrawEvent;
        private Vessel2 myBase;
        private Vessel me;

        public Vessel This
        {
            get { return me; }
            set
            {
                if (me == null)
                {
                    me = value;
                    DeltaGliderCont();
                }
                else me = value;
            }
        }

        public Vessel2 Base
        {
            get { return myBase; }
            set { myBase = value; }
        }

        public Vessel2Callback CallbackSetting
        {
            get { return callbackSetting; }
        }

        public void DisposeThis()
        {
            throw new NotImplementedException();
        }

        private static double[] alpha = new double[] {   -180 * Constants.Radiant,
                                                         -60 * Constants.Radiant,
                                                         -30 * Constants.Radiant,
                                                         -2 * Constants.Radiant,
                                                         15 * Constants.Radiant,
                                                         20 * Constants.Radiant,
                                                         25 * Constants.Radiant,
                                                         60 * Constants.Radiant,
                                                         180 * Constants.Radiant };
        private static double[] verticalCL = new double[] { 0, 0, -0.4, 0, 0.7, 1, 0.8, 0, 0 };
        private static double[] verticalCM = new double[] { 0, 0, 0.014, 0.0039, -0.006, -0.008,
                                            -0.010, 0, 0 };
        private static double[] beta = new double[] { -180 * Constants.Radiant, -135 * Constants.Radiant, -90 * Constants.Radiant, -45 * Constants.Radiant, 45 * Constants.Radiant, 90 * Constants.Radiant, 135 * Constants.Radiant, 180 * Constants.Radiant };
        private static double[] horizontalCL = new double[] { 0, +0.3, 0, -0.3, +0.3, 0, -0.3, 0 };

        /// <summary>
        /// vertical lift component (wings and body)
        /// </summary>
        /// <param name="angleOfAttack"></param>
        /// <param name="mach"></param>
        /// <param name="reynolds"></param>
        /// <param name="contextVoidPointer"></param>
        /// <param name="liftCoefficientDoublePointer"></param>
        /// <param name="momentCoefficientDoublePointer"></param>
        /// <param name="dragCoefficientDoublePointer"></param>
        /// <remarks>
        /// Return lift, moment and zero-lift drag coefficients as a
        /// function of angle of attack (alpha or beta)
        /// </remarks>
        private void VLiftCoeff(double angleOfAttack, double mach, double reynolds, IntPtr contextVoidPointer, IntPtr liftCoefficientDoublePointer, IntPtr momentCoefficientDoublePointer, IntPtr dragCoefficientDoublePointer)
        {
            int i;
            for (i = 0; i < alpha.Length-1 && alpha[i+1] < angleOfAttack; i++);
            double f = (angleOfAttack-alpha[i]) / (alpha[i+1]-alpha[i]);
            double cl = verticalCL[i] + (verticalCL[i+1]-verticalCL[i]) * f;  // angleOfAttack-dependent lift coefficient
            double cm = verticalCM[i] + (verticalCM[i+1]-verticalCM[i]) * f;  // angleOfAttack-dependent moment coefficient
            double saoa = Math.Sin(angleOfAttack);
            double pd = 0.015 + 0.4*saoa*saoa;  // profile drag
            double cd = pd + OAPI.GetInducedDrag (cl, 1.5, 0.7) + OAPI.GetWaveDrag (mach, 0.75, 1.0, 1.1, 0.04);
            // profile drag + (lift-)induced drag + transonic/supersonic wave (compressibility) drag
            Marshal.StructureToPtr(cl, liftCoefficientDoublePointer, true);
            Marshal.StructureToPtr(cm, momentCoefficientDoublePointer, true);
            Marshal.StructureToPtr(cd, dragCoefficientDoublePointer, true);
        }

        /// <summary>
        /// horizontal lift component (vertical stabilisers and body)
        /// </summary>
        /// <param name="angleOfAttack"></param>
        /// <param name="mach"></param>
        /// <param name="reynolds"></param>
        /// <param name="contextVoidPointer"></param>
        /// <param name="liftCoefficientDoublePointer"></param>
        /// <param name="momentCoefficientDoublePointer"></param>
        /// <param name="dragCoefficientDoublePointer"></param>
        /// <remarks>
        /// Return lift, moment and zero-lift drag coefficients as a
        /// function of angle of attack (alpha or beta)
        /// </remarks>
        private void HLiftCoeff(double angleOfAttack, double mach, double reynolds, IntPtr contextVoidPointer, IntPtr liftCoefficientDoublePointer, IntPtr momentCoefficientDoublePointer, IntPtr dragCoefficientDoublePointer)
        {
            int i;
            for (i = 0; i < beta.Length-1 && beta[i+1] < angleOfAttack; i++);
            double cl = horizontalCL[i] + (horizontalCL[i+1]-horizontalCL[i]) * (angleOfAttack-beta[i]) / (beta[i+1]-beta[i]);
            double cm = 0.0;
            double cd = 0.015 +OAPI.GetInducedDrag(cl, 1.5, 0.6) + OAPI.GetWaveDrag(mach, 0.75, 1.0, 1.1, 0.04);
            Marshal.StructureToPtr(cl, liftCoefficientDoublePointer, true);
            Marshal.StructureToPtr(cm, momentCoefficientDoublePointer, true);
            Marshal.StructureToPtr(cd, dragCoefficientDoublePointer, true);
        }
        
        public DeltaGlider(int fmodel)
        {
            int i, j;

            modelidx = (fmodel>0 ? 1 : 0);
            aoa_ind = Math.PI;
            slip_ind = Math.PI * 0.5;
            load_ind = Math.PI;
            gear_status = DoorStatus.CLOSED;
            rcover_status = DoorStatus.CLOSED;
            nose_status = DoorStatus.CLOSED;
            ladder_status = DoorStatus.CLOSED;
            ladder_proc = 0.0;
            olock_status = DoorStatus.CLOSED;
            olock_proc = 0.0;
            ilock_status = DoorStatus.CLOSED;
            ilock_proc = 0.0;
            hatch_status = DoorStatus.CLOSED;
            hatch_proc = 0.0;
            brake_status = DoorStatus.CLOSED;
            radiator_status = DoorStatus.CLOSED;
            visual = IntPtr.Zero;
            exmesh = IntPtr.Zero;
            vcmesh = IntPtr.Zero;
            vcmesh_tpl = IntPtr.Zero;
            scramjet = null;
            hatch_vent = IntPtr.Zero;
            insignia_tex = IntPtr.Zero;
            campos = CameraPositions.GENERIC;

            skinpath = String.Empty;
            for (i = 0; i < skin.Length; i++)
                skin[i] = IntPtr.Zero;
            for (i = 0; i < psngr.Length; i++)
                psngr[i] = false;
            for (i = 0; i < scram_max.Length; i++)
            {
                scram_max[i] = 0.0;
            }
            for (i = 0; i < scgimbalidx.Length; i++)
            {
                scgimbalidx[i] = mpgimbalidx[i] = mygimbalidx[i] = 35;
                scflowidx[i] = 0;
                mainflowidx[i] = retroflowidx[i] = -1;
                scTSFCidx[i] = -1;
                mainpropidx[i] = rcspropidx[i] = scrampropidx[i] = -1;
                mpswitch[i] = myswitch[i] = sgswitch[i] = 0;
            }
            for (i = 0; i < rotidx.Length; i++)
            {
                rotidx[i]=new int[3];
                for (j = 0; j < rotidx[i].Length; j++) rotidx[i][j] = 0;
            }

            mpmode = mymode = spmode = hbmode = hbswitch = 0;
            mainpropmass = rcspropmass = scrampropmass = -1;
            mainTSFCidx = hoverflowidx = -1;
            hbalanceidx = 28;
        }

        /// <summary>
        /// Continued constructor logic AFTER This-property was first set
        /// </summary>
        private void DeltaGliderCont()
        {
            int i;
            
            //Damage system
            bDamageEnabled = (This.DamageModel != 0);
            bMWSActive = bMWSOn = false;
            lwingstatus = rwingstatus = 1.0;
            hatchfail = 0;
            for (i = 0; i < aileronfail.Length; i++) aileronfail[i] = false;
            
            //Animations
            DefineAnimations();
            for (i = 0; i < srf.Length; i++) srf[i] = IntPtr.Zero;
        }
        
        private static int NGRP=117;
        private static int NMAT=27;
        private static int NTEX=10;

        private static int GRP_ILock1=9;
        private static int GRP_ILock2=10;
        private static int GRP_OLock1=11;
        private static int GRP_Hatch1=12;
        private static int GRP_RearLadder1=14;
        private static int GRP_RearLadder2=15;
        private static int GRP_LRudder1=31;
        private static int GRP_LRudder2=32;
        private static int GRP_RRudder1=33;
        private static int GRP_RRudder2=34;
        private static int GRP_RCoverBL1=37;
        private static int GRP_RCoverTL1=38;
        private static int GRP_RCoverBR1=39;
        private static int GRP_RCoverTR1=40;
        private static int GRP_OLock2=41;
        private static int GRP_Radiator1=43;
        private static int GRP_Radiator2=44;
        private static int GRP_NConeDock=45;
        private static int GRP_Ladder1=46;
        private static int GRP_Ladder2=47;
        private static int GRP_Radiator3=49;
        private static int GRP_Raddoor1=53;
        private static int GRP_RWheelOCover1=56;
        private static int GRP_RWheelOCover2=57;
        private static int GRP_RWheelICover1=58;
        private static int GRP_LWheelICover1=59;
        private static int GRP_LWheelOCover1=60;
        private static int GRP_LWheelOCover2=61;
        private static int GRP_NWheelFCover1=62;
        private static int GRP_NWheelLCover1=63;
        private static int GRP_NWheelRCover1=64;
        private static int GRP_RCoverBL2=65;
        private static int GRP_RCoverTL2=66;
        private static int GRP_RCoverBR2=67;
        private static int GRP_RCoverTR2=68;
        private static int GRP_NConeTL1=69;
        private static int GRP_NConeTR1=70;
        private static int GRP_NConeBL1=71;
        private static int GRP_NConeBR1=72;
        private static int GRP_Raddoor2=74;
        private static int GRP_RWheelOCover3=75;
        private static int GRP_RWheelOCover4=76;
        private static int GRP_RWheelICover2=77;
        private static int GRP_LWheelICover2=78;
        private static int GRP_LWheelOCover3=79;
        private static int GRP_LWheelOCover4=80;
        private static int GRP_NWheelFCover2=81;
        private static int GRP_NWheelLCover2=82;
        private static int GRP_NWheelRCover2=83;
        private static int GRP_NConeTL2=84;
        private static int GRP_NConeTR2=85;
        private static int GRP_NConeBL2=86;
        private static int GRP_NConeBR2=87;
        private static int GRP_Hatch2=88;
        private static int GRP_RWheelStrut1=90;
        private static int GRP_LWheelStrut1=91;
        private static int GRP_NWheelStrut1=92;
        private static int GRP_RWheelStrut2=94;
        private static int GRP_LWheelStrut2=95;
        private static int GRP_NWheelStrut2=96;

        
        // ***** Landing gear animation *****
            private static int[] NWheelStrutGrp=new int[]{GRP_NWheelStrut1,GRP_NWheelStrut2};
            private static MeshGroupRotation NWheelStrut=new Wrapper.MeshGroupRotation(0, NWheelStrutGrp, new Vector3(0,-1.048,8.561), new Vector3(1,0,0), (float)(-95*Constants.Radiant));
            private static int[] NWheelFCoverGrp = new int[]{GRP_NWheelFCover1,GRP_NWheelFCover2};
            private static MeshGroupRotation NWheelFCover = new Wrapper.MeshGroupRotation(0,  NWheelFCoverGrp,
                new Vector3(0,-1.145,8.65), new Vector3(1,0,0), (float)(-90*Constants.Radiant));
            private static int[] NWheelLCoverGrp = new int[]{GRP_NWheelLCover1,GRP_NWheelLCover2};
            private static MeshGroupRotation NWheelLCover1 = new Wrapper.MeshGroupRotation(0,  NWheelLCoverGrp,
                new Vector3(-0.3,-1.222,7.029), new Vector3(0,0.052,0.999), (float)(-90*Constants.Radiant));
            private static MeshGroupRotation NWheelLCover2 = new Wrapper.MeshGroupRotation(0,  NWheelLCoverGrp,
                new Vector3(-0.3,-1.222,7.029), new Vector3(0,0.052,0.999), (float)( 90*Constants.Radiant));
            private static int[] NWheelRCoverGrp = new int[]{GRP_NWheelRCover1,GRP_NWheelRCover2};
            private static MeshGroupRotation NWheelRCover1 = new Wrapper.MeshGroupRotation(0,  NWheelRCoverGrp,
                new Vector3( 0.3,-1.222,7.029), new Vector3(0,0.052,0.999), (float)( 90*Constants.Radiant));
            private static MeshGroupRotation NWheelRCover2 = new Wrapper.MeshGroupRotation(0,  NWheelRCoverGrp,
                new Vector3( 0.3,-1.222,7.029), new Vector3(0,0.052,0.999), (float)(-90*Constants.Radiant));
            private static int[] LWheelStrutGrp = new int[]{GRP_LWheelStrut1,GRP_LWheelStrut2};
            private static MeshGroupRotation LWheelStrut = new Wrapper.MeshGroupRotation(0,  LWheelStrutGrp,
                new Vector3(-3.607,-1.137,-3.08), new Vector3(0,0,1), (float)(-90*Constants.Radiant));
            private static int[] RWheelStrutGrp = new int[]{GRP_RWheelStrut1,GRP_RWheelStrut2};
            private static MeshGroupRotation RWheelStrut = new Wrapper.MeshGroupRotation(0,  RWheelStrutGrp,
                new Vector3( 3.607,-1.137,-3.08), new Vector3(0,0,1), (float)(90*Constants.Radiant));
            private static int[] LWheelOCoverGrp = new int[]{GRP_LWheelOCover1,GRP_LWheelOCover2,GRP_LWheelOCover3,GRP_LWheelOCover4};
            private static MeshGroupRotation LWheelOCover = new Wrapper.MeshGroupRotation(0,  LWheelOCoverGrp,
                new Vector3(-3.658,-1.239,-3.038), new Vector3(0,0,1), (float)(-110*Constants.Radiant));
            private static int[] LWheelICoverGrp = new int[]{GRP_LWheelICover1,GRP_LWheelICover2};
            private static MeshGroupRotation LWheelICover1 = new Wrapper.MeshGroupRotation(0,  LWheelICoverGrp,
                new Vector3(-2.175,-1.178,-3.438), new Vector3(0,0,1), (float)(90*Constants.Radiant));
            private static MeshGroupRotation LWheelICover2 = new Wrapper.MeshGroupRotation(0,  LWheelICoverGrp,
                new Vector3(-2.175,-1.178,-3.438), new Vector3(0,0,1), (float)(-90*Constants.Radiant));
            private static int[] RWheelOCoverGrp = new int[]{GRP_RWheelOCover1,GRP_RWheelOCover2,GRP_RWheelOCover3,GRP_RWheelOCover4};
            private static MeshGroupRotation RWheelOCover = new Wrapper.MeshGroupRotation(0,  RWheelOCoverGrp,
                new Vector3( 3.658,-1.239,-3.038), new Vector3(0,0,1), (float)( 110*Constants.Radiant));
            private static int[] RWheelICoverGrp = new int[]{GRP_RWheelICover1,GRP_RWheelICover2};
            private static MeshGroupRotation RWheelICover1 = new Wrapper.MeshGroupRotation(0,  RWheelICoverGrp,
                new Vector3( 2.175,-1.178,-3.438), new Vector3(0,0,1), (float)(-90*Constants.Radiant));
            private static MeshGroupRotation RWheelICover2 = new Wrapper.MeshGroupRotation(0,  RWheelICoverGrp,
                new Vector3(2.175,-1.178,-3.438), new Vector3(0,0,1), (float)( 90*Constants.Radiant));
            // ***** Retro cover animation *****
            private static int[] RCoverTLGrp = new int[]{GRP_RCoverTL1,GRP_RCoverTL2};
            private static MeshGroupRotation RCoverTL = new Wrapper.MeshGroupRotation(0,  RCoverTLGrp,
                new Vector3(-2.156,-0.49,6.886), new Vector3(-0.423,0.23,-0.877), (float)( 70*Constants.Radiant));
            private static int[] RCoverBLGrp = new int[]{GRP_RCoverBL1,GRP_RCoverBL2};
            private static MeshGroupRotation RCoverBL = new Wrapper.MeshGroupRotation(0,  RCoverBLGrp,
                new Vector3(-2.156,-0.49,6.886), new Vector3(-0.434,-0.037,-0.9), (float)(-70*Constants.Radiant));
            private static int[] RCoverTRGrp = new int[]{GRP_RCoverTR1,GRP_RCoverTR2};
            private static MeshGroupRotation RCoverTR = new Wrapper.MeshGroupRotation(0,  RCoverTRGrp,
                new Vector3( 2.156,-0.49,6.886), new Vector3( 0.423,0.23,-0.877), (float)(-70*Constants.Radiant));
            private static int[] RCoverBRGrp = new int[]{GRP_RCoverBR1,GRP_RCoverBR2};
            private static MeshGroupRotation RCoverBR = new Wrapper.MeshGroupRotation(0,  RCoverBRGrp,
                new Vector3( 2.156,-0.49,6.886), new Vector3( 0.434,-0.037,-0.9), (float)( 70*Constants.Radiant));
            
            // ***** Nose cone animation *****
            private static int[] NConeTLGrp = new int[]{GRP_NConeTL1,GRP_NConeTL2};
            private static MeshGroupRotation NConeTL = new Wrapper.MeshGroupRotation(0,  NConeTLGrp,
                new Vector3(-0.424,-0.066,9.838), new Vector3(-0.707,-0.707,0), (float)(150*Constants.Radiant));
            private static int[] NConeTRGrp = new int[]{GRP_NConeTR1,GRP_NConeTR2};
            private static MeshGroupRotation NConeTR = new Wrapper.MeshGroupRotation(0,  NConeTRGrp,
                new Vector3( 0.424,-0.066,9.838), new Vector3(-0.707, 0.707,0), (float)(150*Constants.Radiant));
            private static int[] NConeBLGrp = new int[]{GRP_NConeBL1,GRP_NConeBL2};
            private static MeshGroupRotation NConeBL = new Wrapper.MeshGroupRotation(0,  NConeBLGrp,
                new Vector3(-0.424,-0.914,9.838), new Vector3( 0.707,-0.707,0), (float)(150*Constants.Radiant));
            private static int[] NConeBRGrp = new int[]{GRP_NConeBR1,GRP_NConeBR2};
            private static MeshGroupRotation NConeBR = new Wrapper.MeshGroupRotation(0,  NConeBRGrp,
                new Vector3( 0.424,-0.914,9.838), new Vector3( 0.707, 0.707,0), (float)(150*Constants.Radiant));
            private static int[] NConeDockGrp = new int[]{GRP_NConeDock};
            private static MeshGroupTranslation NConeDock = new Wrapper.MeshGroupTranslation(0, NConeDockGrp, new Vector3(0,0,0.06));
            // virtual cockpit mesh animation (nose cone visible from cockpit)
            private static int[] VCNConeTLGrp = new int[]{106};
            private static MeshGroupRotation VCNConeTL = new Wrapper.MeshGroupRotation(1,  VCNConeTLGrp,
                new Vector3(-0.424,-0.066,9.838), new Vector3(-0.707,-0.707,0), (float)(150*Constants.Radiant));
            private static int[] VCNConeTRGrp = new int[]{107};
            private static MeshGroupRotation VCNConeTR = new Wrapper.MeshGroupRotation(1,  VCNConeTRGrp,
                new Vector3( 0.424,-0.066,9.838), new Vector3(-0.707, 0.707,0), (float)(150*Constants.Radiant));
            // ***** Outer airlock animation *****
            private static int[] OLockGrp = new int[]{GRP_OLock1,GRP_OLock2};
            private static MeshGroupRotation OLock = new Wrapper.MeshGroupRotation(0,  OLockGrp,
                new Vector3(0,-0.080,9.851), new Vector3(1,0,0), (float)(110*Constants.Radiant));
            private static int[] VCOLockGrp = new int[]{13};
            private static MeshGroupRotation VCOLock = new Wrapper.MeshGroupRotation(1,  VCOLockGrp,
                new Vector3(0,-0.080,9.851), new Vector3(1,0,0), (float)(110*Constants.Radiant));
            // ***** Inner airlock animation *****
            private static int[] ILockGrp = new int[]{GRP_ILock1,GRP_ILock2};
            private static MeshGroupRotation ILock = new Wrapper.MeshGroupRotation(0,  ILockGrp,
                new Vector3(0,-0.573,7.800), new Vector3(1,0,0), (float)(85*Constants.Radiant));
            // virtual cockpit mesh animation (inner airlock visible from cockpit)
            private static int[] VCILockGrp = new int[]{10,28,11,127};
            private static MeshGroupRotation VCILock = new Wrapper.MeshGroupRotation(1,  VCILockGrp,
                new Vector3(0,-0.573,7.800), new Vector3(1,0,0), (float)(85*Constants.Radiant));
            // ***** Escape ladder animation *****
            private static int[] LadderGrp = new int[]{GRP_Ladder1,GRP_Ladder2};
            private static MeshGroupTranslation Ladder1 = new Wrapper.MeshGroupTranslation(0, LadderGrp, new Vector3(0,0,1.1));
            private static MeshGroupRotation Ladder2 = new Wrapper.MeshGroupRotation(0,  LadderGrp,
                new Vector3(0,-1.05,9.85), new Vector3(1,0,0), (float)(80*Constants.Radiant));
            // ***** Top hatch animation *****
            private static int[] HatchGrp = new int[]{GRP_Hatch1,GRP_Hatch2};
            private static MeshGroupRotation Hatch = new Wrapper.MeshGroupRotation(0,  HatchGrp,
                new Vector3(0,2.069,5.038), new Vector3(1,0,0), (float)(110*Constants.Radiant));
            private static int[] VCHatchGrp = new int[]{14};
            private static MeshGroupRotation VCHatch = new Wrapper.MeshGroupRotation(1,  VCHatchGrp,
                new Vector3(0,2.069,5.038), new Vector3(1,0,0), (float)(110*Constants.Radiant));
            private static int[] RearLadderGrp = new int[]{GRP_RearLadder1,GRP_RearLadder2};
            private static int[] RearLadderGrp1 = new int[]{GRP_RearLadder2};
            private static MeshGroupRotation RearLadder1 = new Wrapper.MeshGroupRotation(0,  RearLadderGrp,
                new Vector3(0,1.7621,4.0959), new Vector3(1,0,0), (float)(-20*Constants.Radiant));
            private static MeshGroupRotation RearLadder2 = new Wrapper.MeshGroupRotation(0, RearLadderGrp1,
                new Vector3(0,1.1173,4.1894), new Vector3(1,0,0), (float)(180*Constants.Radiant));
            // virtual cockpit ladder animation
            private static int[] VCRearLadderGrp = new int[]{29,30};
            private static int[] VCRearLadderGrp1 = new int[]{30};
            private static MeshGroupRotation VCRearLadder1 = new Wrapper.MeshGroupRotation(1,  VCRearLadderGrp,
                new Vector3(0,1.7621,4.0959), new Vector3(1,0,0), (float)(-20*Constants.Radiant));
            private static MeshGroupRotation VCRearLadder2 = new Wrapper.MeshGroupRotation(1, VCRearLadderGrp1,
                new Vector3(0,1.1173,4.1894), new Vector3(1,0,0), (float)(180*Constants.Radiant));
            // ***** Radiator animation *****
            private static int[] RaddoorGrp = new int[]{GRP_Raddoor1,GRP_Raddoor2};
            private static MeshGroupRotation Raddoor = new Wrapper.MeshGroupRotation(0,  RaddoorGrp,
                new Vector3(0,1.481,-3.986), new Vector3(1,0,0), (float)(170*Constants.Radiant));
            private static int[] RadiatorGrp = new int[]{GRP_Radiator1,GRP_Radiator2,GRP_Radiator3};
            private static MeshGroupTranslation Radiator = new Wrapper.MeshGroupTranslation(0, RadiatorGrp, new Vector3(0,0.584,-0.157));
            private static int[] LRadiatorGrp = new int[]{GRP_Radiator1};
            private static MeshGroupRotation LRadiator = new Wrapper.MeshGroupRotation(0,  LRadiatorGrp,
                new Vector3(-0.88,1.94,-4.211), new Vector3(0,0.260,0.966), (float)(135*Constants.Radiant));
            private static int[] RRadiatorGrp = new int[]{GRP_Radiator2};
            private static MeshGroupRotation RRadiator = new Wrapper.MeshGroupRotation(0,  RRadiatorGrp,
                new Vector3(0.93,1.91,-4.211), new Vector3(0,0.260,0.966), (float)(-135*Constants.Radiant));
            // ***** Rudder animation *****
            private static int[] RRudderGrp = new int[]{GRP_RRudder1,GRP_RRudder2};
            private static MeshGroupRotation RRudder = new Wrapper.MeshGroupRotation(0,  RRudderGrp,
                new Vector3( 8.668,0.958,-6.204), new Vector3( 0.143,0.975,-0.172), (float)(-60*Constants.Radiant));
            private static int[] LRudderGrp = new int[]{GRP_LRudder1,GRP_LRudder2};
            private static MeshGroupRotation LRudder = new Wrapper.MeshGroupRotation(0,  LRudderGrp,
                new Vector3(-8.668,0.958,-6.204), new Vector3(-0.143,0.975,-0.172), (float)(-60*Constants.Radiant));
            // ***** Elevator animation *****
            private static int[] ElevatorGrp = new int[]{29,30,35,36,51,52,54,55};
            private static MeshGroupRotation Elevator = new Wrapper.MeshGroupRotation(0,  ElevatorGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(40*Constants.Radiant));
            // ***** Elevator trim animation *****
            private static MeshGroupRotation ElevatorTrim = new Wrapper.MeshGroupRotation(0,  ElevatorGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(10*Constants.Radiant));
            // ***** Aileron animation *****
            private static int[] LAileronGrp = new int[]{29,30,51,52};
            private static MeshGroupRotation LAileron = new Wrapper.MeshGroupRotation(0,  LAileronGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(-20*Constants.Radiant));
            private static int[] RAileronGrp = new int[]{35,36,54,55};
            private static MeshGroupRotation RAileron = new Wrapper.MeshGroupRotation(0,  RAileronGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(20*Constants.Radiant));
            // ***** Airbrake animation *****
            private static int[] UpperBrakeGrp = new int[]{35,30,52,55};
            private static MeshGroupRotation UpperBrake = new Wrapper.MeshGroupRotation(0,  UpperBrakeGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(30*Constants.Radiant));
            private static int[] LowerBrakeGrp = new int[]{29,36,51,54};
            private static MeshGroupRotation LowerBrake = new Wrapper.MeshGroupRotation(0,  LowerBrakeGrp,
                new Vector3(0,-0.4,-6.0), new Vector3(1,0,0), (float)(-30*Constants.Radiant));
            private static MeshGroupRotation RRudderBrake = new Wrapper.MeshGroupRotation(0,  RRudderGrp,
                new Vector3( 8.668,0.958,-6.204), new Vector3( 0.143,0.975,-0.172), (float)( 25*Constants.Radiant));
            private static MeshGroupRotation LRudderBrake = new Wrapper.MeshGroupRotation(0,  LRudderGrp,
                new Vector3(-8.668,0.958,-6.204), new Vector3(-0.143,0.975,-0.172), (float)(-25*Constants.Radiant));
            // ======================================================
            // VC animation definitions
            // ======================================================

            private static int[] MainThrottleLGrp=new int[]{32,53};
            private static MeshGroupRotation MainThrottleL = new Wrapper.MeshGroupRotation(1,  MainThrottleLGrp,
                new Vector3(0,0.72,6.9856), new Vector3(1,0,0), (float)(50*Constants.Radiant));
            private static int[] MainThrottleRGrp = new int[]{37,54};
            private static MeshGroupRotation MainThrottleR = new Wrapper.MeshGroupRotation(1,  MainThrottleRGrp,
                new Vector3(0,0.72,6.9856), new Vector3(1,0,0), (float)(50*Constants.Radiant));
            private static int[] HoverThrottleGrp = new int[]{38,60};
            private static MeshGroupRotation HoverThrottle = new Wrapper.MeshGroupRotation(1,  HoverThrottleGrp,
                new Vector3(-0.41,0.8222,6.9226), new Vector3(1,0,0), (float)(50*Constants.Radiant));
            private static int[] ScramThrottleLGrp = new int[]{39,61};
            private static MeshGroupRotation ScramThrottleL = new Wrapper.MeshGroupRotation(1,  ScramThrottleLGrp,
                new Vector3(0,0.7849,6.96), new Vector3(1,0,0), (float)(30*Constants.Radiant));
            private static int[] ScramThrottleRGrp = new int[]{40,62};
            private static MeshGroupRotation ScramThrottleR = new Wrapper.MeshGroupRotation(1,  ScramThrottleRGrp,
                new Vector3(0,0.7849,6.96), new Vector3(1,0,0), (float)(30*Constants.Radiant));
            private static int[] GearLeverGrp = new int[]{42,63};
            private static MeshGroupRotation GearLever = new Wrapper.MeshGroupRotation(1,  GearLeverGrp,
                new Vector3(0.3314,0.9542,7.1764), new Vector3(-0.7590,-0.231,0.6087), (float)(110*Constants.Radiant));
            private static int[] NoseconeLeverGrp = new int[]{43,64};
            private static MeshGroupRotation NoseconeLever = new Wrapper.MeshGroupRotation(1,  NoseconeLeverGrp,
                new Vector3(0.35,1.0594,7.1995), new Vector3(-0.7590,-0.231,0.6087), (float)(110*Constants.Radiant));
            private static int[] ScramGimbalLGrp = new int[]{69};
            private static MeshGroupRotation ScramGimbalL = new Wrapper.MeshGroupRotation(1,  ScramGimbalLGrp,
                new Vector3(-0.2620,1.0515,7.2433), new Vector3(0.9439,-0.0828,0.3197), (float)(31*Constants.Radiant));
            private static int[] ScramGimbalRGrp = new int[]{70};
            private static MeshGroupRotation ScramGimbalR = new Wrapper.MeshGroupRotation(1,  ScramGimbalRGrp,
                new Vector3(-0.2501,1.0504,7.2474), new Vector3(0.9439,-0.0828,0.3197), (float)(31*Constants.Radiant));
            private static int[] PMainGimbalLGrp = new int[]{72};
            private static MeshGroupRotation PMainGimbalL = new Wrapper.MeshGroupRotation(1,  PMainGimbalLGrp,
                new Vector3(-0.3682,1.0986,7.1452), new Vector3(0.7139,-0.1231,0.6893), (float)(31*Constants.Radiant));
            private static int[] PMainGimbalRGrp = new int[]{73};
            private static MeshGroupRotation PMainGimbalR = new Wrapper.MeshGroupRotation(1,  PMainGimbalRGrp,
                new Vector3(-0.3587,1.0970,7.1543), new Vector3(0.7139,-0.1231,0.6893), (float)(31*Constants.Radiant));
            private static int[] YMainGimbalLGrp = new int[]{74};
            private static MeshGroupRotation YMainGimbalL = new Wrapper.MeshGroupRotation(1,  YMainGimbalLGrp,
                new Vector3(-0.3638,1.0479,7.1364), new Vector3(-0.0423,0.9733,0.2257), (float)(31*Constants.Radiant));
            private static int[] YMainGimbalRGrp = new int[]{75};
            private static MeshGroupRotation YMainGimbalR = new Wrapper.MeshGroupRotation(1,  YMainGimbalRGrp,
                new Vector3(-0.3633,1.0355,7.1336), new Vector3(-0.0423,0.9733,0.2257), (float)(31*Constants.Radiant));
            private static int[] HBalanceGrp = new int[]{68};
            private static MeshGroupRotation HBalance = new Wrapper.MeshGroupRotation(1,  HBalanceGrp,
                new Vector3(-0.2561,1.1232,7.2678), new Vector3(0.9439,-0.0828,0.3197), (float)(31*Constants.Radiant));
            private static int[] HUDIntensGrp = new int[]{78};
            private static MeshGroupRotation HUDIntens = new Wrapper.MeshGroupRotation(1,  HUDIntensGrp,
                new Vector3(0.2427,1.1504,7.3136), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] RCSDialGrp = new int[]{79};
            private static MeshGroupRotation RCSDial = new Wrapper.MeshGroupRotation(1, RCSDialGrp, 
                new Vector3(-0.3358,1.0683,7.2049), new Vector3(0.3310,0.2352,-0.9138), (float)(100*Constants.Radiant));
            private static int[] AFDialGrp = new int[]{83};
            private static MeshGroupRotation AFDial = new Wrapper.MeshGroupRotation(1,  AFDialGrp,
                new Vector3(-0.3361,1.1152,7.2179), new Vector3(0.3310,0.2352,-0.9138), (float)(100*Constants.Radiant));
            private static int[] OLockSwitchGrp = new int[]{90};
            private static MeshGroupRotation OLockSwitch = new Wrapper.MeshGroupRotation(1,  OLockSwitchGrp,
                new Vector3(0.2506,1.0969,7.2866), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] ILockSwitchGrp = new int[]{93};
            private static MeshGroupRotation ILockSwitch = new Wrapper.MeshGroupRotation(1,  ILockSwitchGrp,
                new Vector3(0.2824,1.1066,7.2611), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] RetroSwitchGrp = new int[]{95};
            private static MeshGroupRotation RetroSwitch = new Wrapper.MeshGroupRotation(1,  RetroSwitchGrp,
                new Vector3(0.2508,1.0505,7.2694), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] LadderSwitchGrp = new int[]{96};
            private static MeshGroupRotation LadderSwitch = new Wrapper.MeshGroupRotation(1,  LadderSwitchGrp,
                new Vector3(0.2889,1.0622,7.2388), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] HatchSwitchGrp = new int[]{97};
            private static MeshGroupRotation HatchSwitch = new Wrapper.MeshGroupRotation(1,  HatchSwitchGrp,
                new Vector3(0.2511,1.0006,7.2507), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
            private static int[] RadiatorSwitchGrp = new int[]{98};
            private static MeshGroupRotation RadiatorSwitch = new Wrapper.MeshGroupRotation(1,  RadiatorSwitchGrp,
                new Vector3(0.2592,0.9517,7.2252), new Vector3(-0.7590,-0.231,0.6087), (float)(31*Constants.Radiant));
        
        /// <summary>
        /// Define animation sequences for moving parts
        /// </summary>
        void DefineAnimations()
        {
            anim_gear = This.CreateAnimation (1);
            This.AddAnimationComponent(anim_gear, 0.3, 1, NWheelStrut);
            This.AddAnimationComponent(anim_gear, 0.3, 0.9, NWheelFCover);
            This.AddAnimationComponent(anim_gear, 0, 0.3, NWheelLCover1);
            This.AddAnimationComponent(anim_gear, 0.7, 1.0, NWheelLCover2);
            This.AddAnimationComponent(anim_gear, 0, 0.3, NWheelRCover1);
            This.AddAnimationComponent(anim_gear, 0.7, 1.0, NWheelRCover2);
            This.AddAnimationComponent(anim_gear, 0, 1, LWheelStrut);
            This.AddAnimationComponent(anim_gear, 0, 1, RWheelStrut);
            This.AddAnimationComponent(anim_gear, 0, 1, LWheelOCover);
            This.AddAnimationComponent(anim_gear, 0, 0.3, LWheelICover1);
            This.AddAnimationComponent(anim_gear, 0.7, 1, LWheelICover2);
            This.AddAnimationComponent(anim_gear, 0, 1, RWheelOCover);
            This.AddAnimationComponent(anim_gear, 0, 0.3, RWheelICover1);
            This.AddAnimationComponent(anim_gear, 0.7, 1, RWheelICover2);

            anim_rcover = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_rcover, 0, 1, RCoverTL);
            This.AddAnimationComponent(anim_rcover, 0, 1, RCoverBL);
            This.AddAnimationComponent(anim_rcover, 0, 1, RCoverTR);
            This.AddAnimationComponent(anim_rcover, 0, 1, RCoverBR);

            anim_nose = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_nose, 0.01, 0.92, NConeTL);
            This.AddAnimationComponent(anim_nose, 0.01, 0.92, VCNConeTL);
            This.AddAnimationComponent(anim_nose, 0.03, 0.91, NConeTR);
            This.AddAnimationComponent(anim_nose, 0.03, 0.91, VCNConeTR);
            This.AddAnimationComponent(anim_nose, 0, 0.89, NConeBL);
            This.AddAnimationComponent(anim_nose, 0.03, 0.94, NConeBR);
            This.AddAnimationComponent(anim_nose, 0.8, 1, NConeDock);

            anim_olock = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_olock, 0, 1, OLock);
            This.AddAnimationComponent(anim_olock, 0, 1, VCOLock);

            anim_ilock = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_ilock, 0, 1, ILock);
            This.AddAnimationComponent(anim_ilock, 0, 1, VCILock);

            anim_ladder = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_ladder, 0, 0.5, Ladder1);
            This.AddAnimationComponent(anim_ladder, 0.5, 1, Ladder2);

            anim_hatch = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_hatch, 0, 1, Hatch);
            This.AddAnimationComponent(anim_hatch, 0, 1, VCHatch);
            This.AddAnimationComponent(anim_hatch, 0, 0.25, RearLadder1);
            This.AddAnimationComponent(anim_hatch, 0.25, 0.8, RearLadder2);
            This.AddAnimationComponent(anim_hatch, 0, 0.25, VCRearLadder1);
            This.AddAnimationComponent(anim_hatch, 0.25, 0.8, VCRearLadder2);

            anim_radiator = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_radiator, 0, 0.33, Raddoor);
            This.AddAnimationComponent(anim_radiator, 0.25, 0.5, Radiator);
            This.AddAnimationComponent(anim_radiator, 0.5, 0.75, RRadiator);
            This.AddAnimationComponent(anim_radiator, 0.75, 1, LRadiator);

            anim_rudder = This.CreateAnimation(0.5);
            This.AddAnimationComponent(anim_rudder, 0, 1, RRudder);
            This.AddAnimationComponent(anim_rudder, 0, 1, LRudder);

            anim_elevator = This.CreateAnimation(0.5);
            This.AddAnimationComponent(anim_elevator, 0, 1, Elevator);

            anim_elevatortrim = This.CreateAnimation(0.5);
            This.AddAnimationComponent(anim_elevatortrim, 0, 1, ElevatorTrim);

            anim_laileron = This.CreateAnimation(0.5);
            This.AddAnimationComponent(anim_laileron, 0, 1, LAileron);

            anim_raileron = This.CreateAnimation(0.5);
            This.AddAnimationComponent(anim_raileron, 0, 1, RAileron);

            anim_brake = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_brake, 0, 1, UpperBrake);
            This.AddAnimationComponent(anim_brake, 0, 1, LowerBrake);
            This.AddAnimationComponent(anim_brake, 0, 1, RRudderBrake);
            This.AddAnimationComponent(anim_brake, 0, 1, LRudderBrake);

            anim_mainthrottle[0] = This.CreateAnimation(0.4);
            This.AddAnimationComponent(anim_mainthrottle[0], 0, 1, MainThrottleL);

            anim_mainthrottle[1] = This.CreateAnimation(0.4);
            This.AddAnimationComponent(anim_mainthrottle[1], 0, 1, MainThrottleR);

            anim_hoverthrottle = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_hoverthrottle, 0, 1, HoverThrottle);

            anim_scramthrottle[0] = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_scramthrottle[0], 0, 1, ScramThrottleL);

            anim_scramthrottle[1] = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_scramthrottle[1], 0, 1, ScramThrottleR);

            anim_gearlever = This.CreateAnimation(1);
            This.AddAnimationComponent(anim_gearlever, 0, 1, GearLever);

            anim_nconelever = This.CreateAnimation(0);
            This.AddAnimationComponent(anim_nconelever, 0, 1, NoseconeLever);

            anim_scramgimbal[0] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_scramgimbal[0], 0, 1, ScramGimbalL);

            anim_scramgimbal[1] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_scramgimbal[1], 0, 1, ScramGimbalR);

            anim_pmaingimbal[0] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_pmaingimbal[0], 0, 1, PMainGimbalL);

            anim_pmaingimbal[1] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_pmaingimbal[1], 0, 1, PMainGimbalR);

            anim_ymaingimbal[0] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_ymaingimbal[0], 0, 1, YMainGimbalL);

            anim_ymaingimbal[1] = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_ymaingimbal[1], 0, 1, YMainGimbalR);

            anim_hbalance = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_hbalance, 0, 1, HBalance);

            anim_hudintens = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_hudintens, 0, 1, HUDIntens);

            anim_rcsdial = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_rcsdial, 0, 1, RCSDial);

            anim_afdial = This.CreateAnimation (0.5);
            This.AddAnimationComponent (anim_afdial, 0, 1, AFDial);

            anim_olockswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_olockswitch, 0, 1, OLockSwitch);

            anim_ilockswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_ilockswitch, 0, 1, ILockSwitch);

            anim_retroswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_retroswitch, 0, 1, RetroSwitch);

            anim_ladderswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_ladderswitch, 0, 1, LadderSwitch);

            anim_hatchswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_hatchswitch, 0, 1, HatchSwitch);

            anim_radiatorswitch = This.CreateAnimation (1);
            This.AddAnimationComponent (anim_radiatorswitch, 0, 1, RadiatorSwitch);
        }

        IntPtr[] th_att_rot = new IntPtr[4];
        IntPtr[] th_att_lin = new IntPtr[4];

        private IntPtr[] MapRCS(bool linear, params int[] values)
        {
            IntPtr[] result = new IntPtr[values.Length];
            if (linear) for (int i = 0; i < values.Length; i++) result[i] = th_att_lin[values[i]];
            else for (int i = 0; i < values.Length; i++) result[i] = th_att_rot[values[i]];
            return result;
        }
        
        private static Vector3[] beaconpos = new Vector3[]
            {   
                new Vector3(-8.6,0,-3.3),
                new Vector3(8.6,0,-3.3),
                new Vector3(0,0.5,-7.5), 
                new Vector3(0,2.2,2),
                new Vector3(0,-1.4,2),
                new Vector3(-8.9,2.5,-5.4),
                new Vector3(8.9,2.5,-5.4),
                new Vector3(0,-1.8,2)
            };
        private static Vector3[] beaconcol = new Vector3[]
            {
                new Vector3(1.0,0.5,0.5),
                new Vector3(0.5,1.0,0.5),
                new Vector3(1,1,1),
                new Vector3(1,0.6,0.6),
                new Vector3(1,0.6,0.6),
                new Vector3(1,1,1),
                new Vector3(1,1,1)
            };

        public void SetClassCaps(IntPtr configuration)
        {
            // *************** physical parameters **********************

            bool b = false;
            if (OAPI.ReadItem(configuration, "SCRAMJET", ref b) && b) // set up scramjet configuration
                scramjet = new Ramjet(This);
            This.EmptyMass = scramjet != null ? EMPTY_MASS_SC : EMPTY_MASS;
            Vector3[] r = new Vector3[] { new Vector3(0, 0, 6), new Vector3(0, 0, -4) };
            This.Size = 10.0;
            This.SetVisibilityLimit(7.5e-4, 1.5e-3);
            This.AlbedoRGB = new Vector3(0.77, 0.20, 0.13);
            This.GravityGradientDamping = 20.0;
            This.CW = new CW(0.09, 0.09, 2, 1.4);
            This.WingAspect = 0.7;
            This.WingEffectiveness = 2.5;
            This.CrossSections = new Vector3(53.0, 186.9, 25.9);
            This.SetSurfaceFrictionCoefficients(0.07, 0.3);
            This.MaxWheelbrakeForce = 2e5;
            This.PMI = new Vector3(15.5, 22.1, 7.7);

            This.SetDockParameters(new DockParameters(new Vector3(0, -0.49, 10.076), new Vector3(0, 0, 1), new Vector3(0, 1, 0)));
            This.TouchDownPoints = new TouchDownPoints(new Vector3(0, -2.57, 10), new Vector3(-3.5, -2.57, -3), new Vector3(3.5, -2.57, -3));
            This.IsTransponderEnabled = true;
            bool render_cockpit = true;

            // ******************** NAV radios **************************

            This.InitNavRadios (4);

            // ****************** propellant specs **********************

            tankconfig = 0; // provide rocket fuel only by default
            max_scramfuel = 0.0;
            max_rocketfuel = TANK1_CAPACITY + TANK2_CAPACITY;

            ph_main = This.CreatePropellantResource(max_rocketfuel);    // main tank (fuel + oxydant)
            ph_rcs = This.CreatePropellantResource(RCS_FUEL_CAPACITY); // RCS tank  (fuel + oxydant)
            if (scramjet != null)
                ph_scram = This.CreatePropellantResource(max_scramfuel); // scramjet fuel

            // **************** thruster definitions ********************

            double ispscale = (modelidx != 0 ? 0.8 : 1.0);
            // Reduction of thrust efficiency at normal pressure

            ParticleStreamSpecification contrail = new ParticleStreamSpecification(
                0, 8.0, 3.0, 150.0, 0.3, 3.5, 4.0, 3.0, ParticleStreamSpecification.LightType.Diffuse,
                ParticleStreamSpecification.LevelMap.LimitedSquareRoot, 0.0, 2.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-4, 1.0, IntPtr.Zero);
            ParticleStreamSpecification exhaust_main = new ParticleStreamSpecification(
                0, 2.0, 10.0, 150.0, 0.1, 0.2, 16.0, 1.0, ParticleStreamSpecification.LightType.Emissive,
                ParticleStreamSpecification.LevelMap.SquareRoot, 0.0, 1.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-5, 0.1, IntPtr.Zero);
            ParticleStreamSpecification exhaust_hover = new ParticleStreamSpecification(
                0, 1.5, 20.0, 150.0, 0.1, 0.15, 9.0, 1.0, ParticleStreamSpecification.LightType.Emissive,
                ParticleStreamSpecification.LevelMap.SquareRoot, 0.0, 1.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-5, 0.1, IntPtr.Zero);
            ParticleStreamSpecification exhaust_scram = new ParticleStreamSpecification(
                0, 2.0, 10.0, 150.0, 0.1, 0.2, 16.0, 1.0, ParticleStreamSpecification.LightType.Emissive,
                ParticleStreamSpecification.LevelMap.SquareRoot, 0.0, 1.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-5, 0.1, IntPtr.Zero);

            // main thrusters
            th_main[0] = This.CreateThruster(new Vector3(-1, 0.0, -7.7), new Vector3(0, 0, 1), MAX_MAIN_THRUST[modelidx], ph_main, ISP, ISP * ispscale);
            th_main[1] = This.CreateThruster(new Vector3(1, 0.0, -7.7), new Vector3(0, 0, 1), MAX_MAIN_THRUST[modelidx], ph_main, ISP, ISP * ispscale);
            thg_main = This.CreateThrusterGroup(th_main, ThrusterGroup.Main);
            This.AddExhaust(th_main[0], 12, 1);
            This.AddExhaust(th_main[1], 12, 1);
            This.AddExhaustStream(th_main[0], new Vector3(-1, 0, -15), contrail);
            This.AddExhaustStream(th_main[1], new Vector3(1, 0, -15), contrail);
            This.AddExhaustStream(th_main[0], new Vector3(-1, 0, -10), exhaust_main);
            This.AddExhaustStream(th_main[1], new Vector3(1, 0, -10), exhaust_main);
            //DWORD i = GetGroupThrusterCount (THGROUP_MAIN);

            // retro thrusters
            // note that we have to tilt retros slightly downwards to avoid inducing
            // an angular momentum, since they are mounted below the level of CG.
            // This also means that retros will induce an upward linear component.
            th_retro[0] = This.CreateThruster(new Vector3(-3, -0.236, 5.6), new Vector3(0, 0.04210548, -0.99911317), MAX_RETRO_THRUST, ph_main, ISP, ISP * ispscale);
            th_retro[1] = This.CreateThruster(new Vector3(3, -0.236, 5.6), new Vector3(0, 0.04210548, -0.99911317), MAX_RETRO_THRUST, ph_main, ISP, ISP * ispscale);
            thg_retro = This.CreateThrusterGroup(th_retro, ThrusterGroup.Retro);
            This.AddExhaust(th_retro[0], 3, 0.4);
            This.AddExhaust(th_retro[1], 3, 0.4);

            // hover thrusters (simplified)
            // The two aft hover engines are combined into a single "logical" thrusters,
            // but exhaust is rendered separately for both
            th_hover[0] = This.CreateThruster(new Vector3(0, 0, 3), new Vector3(0, 1, 0), MAX_HOVER_THRUST[modelidx], ph_main, ISP, ISP * ispscale);
            th_hover[1] = This.CreateThruster(new Vector3(0, 0, -3), new Vector3(0, 1, 0), MAX_HOVER_THRUST[modelidx], ph_main, ISP, ISP * ispscale);
            thg_hover = This.CreateThrusterGroup(th_hover, ThrusterGroup.Hover);
            This.AddExhaust(th_hover[0], 6, 0.5, new Vector3(0, -1.6, 3), new Vector3(0, -1, 0));
            This.AddExhaust(th_hover[1], 6, 0.5, new Vector3(-3, -1.3, -4.55), new Vector3(0, -1, 0));
            This.AddExhaust(th_hover[1], 6, 0.5, new Vector3(3, -1.3, -4.55), new Vector3(0, -1, 0));
            This.AddExhaustStream(th_hover[0], new Vector3(0, -4, 0), contrail);
            This.AddExhaustStream(th_hover[0], new Vector3(0, -2, 3), exhaust_hover);
            This.AddExhaustStream(th_hover[0], new Vector3(-3, -2, -4.55), exhaust_hover);
            This.AddExhaustStream(th_hover[0], new Vector3(3, -2, -4.55), exhaust_hover);

            // set of attitude thrusters (idealised). The arrangement is such that no angular
            // momentum is created in linear mode, and no linear momentum is created in rotational mode.
            th_att_rot[0] = th_att_lin[0] = This.CreateThruster(new Vector3(0, 0, 8), new Vector3(0, 1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[1] = th_att_lin[3] = This.CreateThruster(new Vector3(0, 0, -8), new Vector3(0, -1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[2] = th_att_lin[2] = This.CreateThruster(new Vector3(0, 0, 8), new Vector3(0, -1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[3] = th_att_lin[1] = This.CreateThruster(new Vector3(0, 0, -8), new Vector3(0, 1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            This.CreateThrusterGroup(MapRCS(false, 0, 1), ThrusterGroup.PitchUp);
            This.CreateThrusterGroup(MapRCS(false, 2, 3), ThrusterGroup.PitchDown);
            This.CreateThrusterGroup(MapRCS(true, 0, 1), ThrusterGroup.Up);
            This.CreateThrusterGroup(MapRCS(true, 2, 3), ThrusterGroup.PitchDown);
            This.AddExhaust(th_att_rot[0], 0.6, 0.078, new Vector3(-0.75, -0.7, 9.65), new Vector3(0, -1, 0));
            This.AddExhaust(th_att_rot[0], 0.6, 0.078, new Vector3(0.75, -0.7, 9.65), new Vector3(0, -1, 0));
            This.AddExhaust(th_att_rot[1], 0.79, 0.103, new Vector3(-0.1, 0.55, -7.3), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[1], 0.79, 0.103, new Vector3(0.1, 0.55, -7.3), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[2], 0.6, 0.078, new Vector3(-0.8, -0.25, 9.6), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[2], 0.6, 0.078, new Vector3(0.8, -0.25, 9.6), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[3], 0.79, 0.103, new Vector3(-0.1, -0.55, -7.3), new Vector3(0, -1, 0));
            This.AddExhaust(th_att_rot[3], 0.79, 0.103, new Vector3(0.1, -0.55, -7.3), new Vector3(0, -1, 0));

            th_att_rot[0] = th_att_lin[0] = This.CreateThruster(new Vector3(0, 0, 6), new Vector3(-1, 0, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[1] = th_att_lin[3] = This.CreateThruster(new Vector3(0, 0, -6), new Vector3(1, 0, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[2] = th_att_lin[2] = This.CreateThruster(new Vector3(0, 0, 6), new Vector3(1, 0, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[3] = th_att_lin[1] = This.CreateThruster(new Vector3(0, 0, -6), new Vector3(-1, 0, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            This.CreateThrusterGroup(MapRCS(false, 0, 1), ThrusterGroup.YawLeft);
            This.CreateThrusterGroup(MapRCS(false, 2, 3), ThrusterGroup.YawRight);
            This.CreateThrusterGroup(MapRCS(true, 0, 1), ThrusterGroup.Left);
            This.CreateThrusterGroup(MapRCS(true, 2, 3), ThrusterGroup.Right);
            This.AddExhaust(th_att_rot[0], 0.6, 0.078, new Vector3(1.0, -0.48, 9.35), new Vector3(1, 0, 0));
            This.AddExhaust(th_att_rot[1], 0.94, 0.122, new Vector3(-2.2, 0.2, -6.0), new Vector3(-1, 0, 0));
            This.AddExhaust(th_att_rot[2], 0.6, 0.078, new Vector3(-1.0, -0.48, 9.35), new Vector3(-1, 0, 0));
            This.AddExhaust(th_att_rot[3], 0.94, 0.122, new Vector3(2.2, 0.2, -6.0), new Vector3(1, 0, 0));

            th_att_rot[0] = This.CreateThruster(new Vector3(6, 0, 0), new Vector3(0, 1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[1] = This.CreateThruster(new Vector3(-6, 0, 0), new Vector3(0, -1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[2] = This.CreateThruster(new Vector3(-6, 0, 0), new Vector3(0, 1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_rot[3] = This.CreateThruster(new Vector3(6, 0, 0), new Vector3(0, -1, 0), MAX_RCS_THRUST, ph_rcs, ISP);
            This.CreateThrusterGroup(MapRCS(false, 0, 1), ThrusterGroup.BankLeft);
            This.CreateThrusterGroup(MapRCS(false, 2, 3), ThrusterGroup.BankRight);
            This.AddExhaust(th_att_rot[0], 1.03, 0.134, new Vector3(-5.1, 0.2, 0.4), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[1], 1.03, 0.134, new Vector3(5.1, -0.8, 0.4), new Vector3(0, -1, 0));
            This.AddExhaust(th_att_rot[2], 1.03, 0.134, new Vector3(5.1, 0.2, 0.4), new Vector3(0, 1, 0));
            This.AddExhaust(th_att_rot[3], 1.03, 0.134, new Vector3(-5.1, -0.8, 0.4), new Vector3(0, -1, 0));

            th_att_lin[0] = This.CreateThruster(new Vector3(0, 0, -7), new Vector3(0, 0, 1), 2 * MAX_RCS_THRUST, ph_rcs, ISP);
            th_att_lin[1] = This.CreateThruster(new Vector3(0, 0, 7), new Vector3(0, 0, -1), 2 * MAX_RCS_THRUST, ph_rcs, ISP);
            This.CreateThrusterGroup(MapRCS(true, 0), ThrusterGroup.Forward);
            This.CreateThrusterGroup(MapRCS(true, 1), ThrusterGroup.Back);
            This.AddExhaust(th_att_lin[0], 0.6, 0.078, new Vector3(0, -0.2, -7.6), new Vector3(0, 0, -1));
            This.AddExhaust(th_att_lin[0], 0.6, 0.078, new Vector3(0, 0.22, -7.6), new Vector3(0, 0, -1));
            This.AddExhaust(th_att_lin[1], 0.6, 0.078, new Vector3(-0.82, -0.49, 9.8), new Vector3(0, 0, 1));
            This.AddExhaust(th_att_lin[1], 0.6, 0.078, new Vector3(0.82, -0.49, 9.8), new Vector3(0, 0, 1));

            // **************** scramjet definitions ********************

            if (scramjet!=null)
            {
                Vector3 dir = new Vector3( 0.0, Math.Sin(SCRAM_DEFAULT_DIR), Math.Cos(SCRAM_DEFAULT_DIR) );

                for (int i = 0; i < 2; i++)
                {
                    th_scram[i] = This.CreateThruster(new Vector3(i>0 ? 0.9 : -0.9, -0.8, -5.6), dir, 0, ph_scram, 0);
                    scramjet.AddThrusterDefinition(th_scram[i], SCRAM_FHV[modelidx],
                        SCRAM_INTAKE_AREA, SCRAM_TEMAX[modelidx], SCRAM_MAX_DMF[modelidx]);
                }

                // thrust rating and ISP for scramjet engines are updated continuously
                //AddExhaust (th_scram[0], 10.0, 0.5);
                //AddExhaust (th_scram[1], 10.0, 0.5);
                IntPtr ph = This.AddExhaustStream(th_scram[0], new Vector3(-1, -1.1, -5.4), exhaust_scram);
                if (ph!=IntPtr.Zero) OAPI.ParticleSetLevelReference(ph, scram_intensity[0]=new DoublePointer());
                ph = This.AddExhaustStream(th_scram[1], new Vector3(1, -1.1, -5.4), exhaust_scram);
                if (ph != IntPtr.Zero) OAPI.ParticleSetLevelReference(ph, scram_intensity[1] = new DoublePointer());
            }

            // ********************* aerodynamics ***********************

            hwing = This.CreateAirfoil3(AirFoilOrientation.Vertical, new Vector3(0, 0, -0.3), VLiftCoeff, 0, 5, 90, 1.5);
            // wing and body lift+drag components

            This.CreateAirfoil3(AirFoilOrientation.Horizontal, new Vector3(0, 0, -4), HLiftCoeff, 0, 5, 15, 1.5);
            // vertical stabiliser and body lift and drag components

            This.CreateControlSurface(ControlSurface.Elevator, 1.4, 1.5, new Vector3(0, 0, -7.2), Constants.AIRCTRL_AXIS_XPOS, anim_elevator);
            This.CreateControlSurface(ControlSurface.Rudder, 0.8, 1.5, new Vector3(0, 0, -7.2), Constants.AIRCTRL_AXIS_YPOS, anim_rudder);
            hlaileron = This.CreateControlSurface2(ControlSurface.Aileron, 0.3, 1.5, new Vector3(7.5, 0, -7.2), Constants.AIRCTRL_AXIS_XPOS, anim_raileron);
            hraileron = This.CreateControlSurface2(ControlSurface.Aileron, 0.3, 1.5, new Vector3(-7.5, 0, -7.2), Constants.AIRCTRL_AXIS_XNEG, anim_laileron);
            This.CreateControlSurface(ControlSurface.ElevatorTrim, 0.3, 1.5, new Vector3(0, 0, -7.2), Constants.AIRCTRL_AXIS_XPOS, anim_elevatortrim);

            This.CreateVariableDragElement(gear_proc = new DoublePointer(), 0.8, new Vector3(0, -1, 0));     // landing gear
            This.CreateVariableDragElement(rcover_proc = new DoublePointer(), 0.2, new Vector3(0, -0.5, 6.5)); // retro covers
            This.CreateVariableDragElement(nose_proc = new DoublePointer(), 3, new Vector3(0, 0, 8));        // nose cone
            This.CreateVariableDragElement(radiator_proc = new DoublePointer(), 1, new Vector3(0, 1.5, -4));   // radiator
            This.CreateVariableDragElement(brake_proc = new DoublePointer(), 4, new Vector3(0, 0, -8));        // airbrake

            This.RotationalDrag = new Vector3(0.10, 0.13, 0.04);
            // angular damping

            // ************************* mesh ***************************

            // ********************* beacon lights **********************
            for (int i = 0; i < 7; i++) {
                beacon[i].Shape = (i < 3 ? Constants.BEACONSHAPE_DIFFUSE : Constants.BEACONSHAPE_STAR);
                beacon[i].Position = beaconpos[i];
                beacon[i].Color = beaconcol[i];
                beacon[i].Size = (i < 3 ? 0.3 : 0.55);
                beacon[i].FallOff = (i < 3 ? 0.4 : 0.6);
                beacon[i].Period = (i < 3 ? 0 : i < 5 ? 2 : 1.13);
                beacon[i].Duration = (i < 5 ? 0.1 : 0.05);
                beacon[i].TimeOffset = (6-i)*0.2;
                beacon[i].Active = false;
                This.AddBeacon (beacon[i]);
            }
            if (scramjet!=null) beacon[4].Position = beaconpos[7];

            This.SetMeshVisibilityMode (This.AddMesh (exmesh_tpl = OAPI.LoadMeshGlobal (scramVersion ? "DG\\deltaglider" : "DG\\deltaglider_ns")), Constants.MESHVIS_EXTERNAL);
            This.SetMeshVisibilityMode (This.AddMesh (vcmesh_tpl = OAPI.LoadMeshGlobal ("DG\\DeltaGliderCockpit")), Constants.MESHVIS_VC);

            // **************** vessel-specific insignia ****************

            insignia_tex = OAPI.CreateTextureSurface(256, 256);
            IntPtr hTex = OAPI.GetTextureHandle(exmesh_tpl, 5);
            if (hTex!=IntPtr.Zero) OAPI.Blt(insignia_tex, hTex, 0, 0, 0, 0, 256, 256);
        }

        public void SaveState(IntPtr scenario)
        {
            throw new NotImplementedException();
        }

        public void LoadStateEx(IntPtr scenario, IntPtr status)
        {
            throw new NotImplementedException();
        }

        public void SetStateEx(VesselStatus2 status)
        {
            throw new NotImplementedException();
        }

        public void PostCreation()
        {
            throw new NotImplementedException();
        }

        public void FocusChanged(bool getFocus, IntPtr newVessel, IntPtr oldVessel)
        {
            throw new NotImplementedException();
        }

        public void PreStep(double simt, double simdt, double mjd)
        {
            throw new NotImplementedException();
        }

        public void PostStep(double simt, double simdt, double mjd)
        {
            throw new NotImplementedException();
        }

        public bool PlaybackEvent(double simt, double event_t, string event_type, string event_name)
        {
            throw new NotImplementedException();
        }

        public void VisualCreated(IntPtr vis, int refCount)
        {
            throw new NotImplementedException();
        }

        public void VisualDestroyed(IntPtr vis, int refCount)
        {
            throw new NotImplementedException();
        }

        public void DrawHUD(int mode, HudPaintSpecification hps, IntPtr hDC)
        {
            // draw the default HUD
	        Base.DrawHUD (mode, hps, hDC);

            Graphics g = Graphics.FromHdc(hDC);

	        // show gear deployment status
	        if (gear_status == DoorStatus.OPEN || (gear_status >= DoorStatus.CLOSING && Math.IEEERemainder(OAPI.SimTime, 1.0) < 0.5))
	        {
		        int d = hps.Markersize/2;
		        int cx = hps.CX, cy = hps.CY;
		        if (cx >= -d*3 && cx < hps.W+d*3 && cy >= d && cy < hps.H+d*5)
		        {
		            
		            g.DrawRectangle(Pens.Green, cx-d/2, cy-d*5, cx+d/2, cy-d*4);
                    g.DrawRectangle(Pens.Green, cx - d * 3, cy - d * 2, cx - d * 2, cy - d);
                    g.DrawRectangle(Pens.Green, cx + d * 2, cy - d * 2, cx + d * 3, cy - d);
		        }
	        }
            
            
            // show RCS mode
	        if (OAPI.CockpitMode == CockpitMode.Virtual)
	        {
                switch (This.AttitudeMode)
                {
                    case AttitudeMode.Rotation:
                        g.DrawString("RCS ROT", SystemFonts.DefaultFont, Brushes.Green, 0, hps.H - 13);
                        break;
                    case AttitudeMode.Translation:
                        g.DrawString("RCS_LIN", SystemFonts.DefaultFont, Brushes.Green, 0, hps.H - 13);
                        break;
                }
	        }
        }

        public void RCSMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void ADCtrlMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void HUDMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void MFDMode(int mfd, int mode)
        {
            throw new NotImplementedException();
        }

        public void NavMode(int mode, bool active)
        {
            throw new NotImplementedException();
        }

        public void DockEvent(int dock, IntPtr mate)
        {
            throw new NotImplementedException();
        }

        public void Animate(double simt)
        {
            throw new NotImplementedException();
        }

        public int ConsumeDirectKey(IntPtr keyState)
        {
            throw new NotImplementedException();
        }

        public int ConsumeBufferedKey(int key, bool down, IntPtr keyState)
        {
            throw new NotImplementedException();
        }

        public bool LoadGenericCockpit()
        {
            throw new NotImplementedException();
        }

        public bool LoadPanel(int id)
        {
            throw new NotImplementedException();
        }

        public bool PanelMouseEvent(int id, int mouseEvent, int mx, int my)
        {
            throw new NotImplementedException();
        }

        public bool PanelRedrawEvent(int id, int mouseEvent, IntPtr surface)
        {
            throw new NotImplementedException();
        }

        public bool LoadVC(int id)
        {
            throw new NotImplementedException();
        }

        public bool VCMouseEvent(int id, int mouseEvent, Vector3 p)
        {
            throw new NotImplementedException();
        }

        public bool VCRedrawEvent(int id, int mouseEvent, IntPtr surface)
        {
            throw new NotImplementedException();
        }
        
        private bool scramVersion
        {
            get
            {
                return scramjet != null;
            }
        }
    }
}