Frankeincoder

a practical .dll writing tutorial for Orbiter ships

by Art Eaton


Prerequisites:

This tutorial assumes that you have created a .dll compiler from the orbiter forum thread, or otherwise have access to a C++ compiler such as the FREE Visual Studio 8 2005 C++ compiler by Microsoft:

http://www.orbiterwiki.org/wiki/Free_Compiler_Setup#Get_the_Compiler

If you are using that compiler, you should also add a link to the runtime environment environment. The audience is also expected to have familiarity with .ini and .cfg files, as many of the concepts used to write those files are needed here. This is a nuts and bolts tutorial for intermediate non programmer developers (like myself).

Credits: Code for lift components were taken from the Orbiter SDK sample source code for the Delta Glider. Orbiter Space Simulator is the intellectual property of Martin Schweiger. The source code from the ShuttlePB was used to create most of the other functions.

You should also have the Orbiter SDK, and be familiar with the contents to some limited degree. Even if the stuff is gobbletygook when you read it, skim it and some terms and concepts of what is possible in orbiter will rub off on you. More understanding will come.

Introduction


Question: What is the relative level of difficulty in writing a .dll by template versus writing an .ini or .cfg file?


Answer: Depends. You need exactly the same data for both, however, the config files do not allow you to do much, so you need little information. The .ini files used by customizable .dll's are also limited. This means that you don't need ALL the data for the ship to work. Writing your own .dll requires more things, but the format is no harder to use than in a config or ini file. If you have a Template to use, writing a .dll is no harder than an .ini file. Writing your own .dll directly gives you the ability to alter many things not currently offered by customizable .dll's such as spacecraft3.dll by Vinka.


A .cpp file is a ordinary text file given the extension name of .cpp to let a compiler know that it is a text file written in C Plus Plus language. It is used by the compiler program to create the .dll (dynamic Link Library)The format of a .cpp is very confusing to the non programmer. The formats used in the sample .cpp's do not match up directly with the instructions in the A.P.I. in a way that is obvious to a non programmer. We are going to break down a .cpp file into three part types (real programmers might want to hide their eyes and put their fingers in their ears right about now):


Code type 1: Stuff we will not change in the .cpp file template. This stuff will be in plain black text in the template. You must follow the format of these things copying all usages of punctuation, and capitalization...for now.


Code type 2. This stuff is highlighted in yellow. These are variables that will be different for every ship. A lot of these variables will be recognizable to those with experience in .cfg files. Ship and mesh file names, landing points, cross sections, and pmi are some of the variables you can modify.


Code type 3. This stuff is highlighted in a variety of colors that indicate what ship systems it applies to. If the stuff is used by two or more systems, the code will be striped with the applicable colors. These are optional components that may or may not be included in a ship design. The colors include: Red=main thrusters, Blue=hover thrusters, Brown=Retro thrusters, Green=RCS thrusters.

An example of a multicolored variable would be the name of a tank that supplies fuel to both main engines and RCS thrusters. This being the Basic Tutorial, you will only find Red, Yellow, and Green used here. Note, you don't NEED to change the names of things, only the numbers that you want. The colors mostly indicate things that it is OK to change and customize, but and name changed must also be changed throughout the file.


Writing the Module


All right, to help out your eyes, from this part on all tutorial instructions will be written in Purple. Note that in a compiler text editor, any notes in it that are not part of the code will be preceeded by //. Data that will not be compiled will then (usually) be highlighted green in your editor program. You can see this by opening the sample .cpp file that goes with this tutorial (FrankeincoderBasic.cpp) using your compiler editor program. I recommend just printing a color copy of this tutorial, and then using it to modify the example .cpp file.

OK, take a deep breath. Let's put in some code. Copy the following to your .cpp file, or just read it if you are using the pre-made example:



#define STRICT

#define ORBITER_MODULE


#include "orbitersdk.h"



Next, we are going to stick in some of the Code Type 2 material, in which you will provide the entries in yellow. In this example, the name of the ship is STARSHIP. You can see that most of this stuff correlates directly to .ini and config files. You can refer to the Orbiter API reference for more information on all of these perameters. Some of this stuff refers to other files to give this ship pre-made control definitions, such as the standard orbiter designations of main, hover, retro and rcs thrusters, and the keyboard controls they use.





class STARSHIP: public VESSEL2 {

public:

STARSHIP (OBJHANDLE hVessel, int flightmodel)

: VESSEL2 (hVessel, flightmodel) {}

void clbkSetClassCaps (FILEHANDLE cfg);

};



void STARSHIP::clbkSetClassCaps (FILEHANDLE cfg)

{

SetSize (25);

SetEmptyMass (100000);

SetCW (0.09, 1.0, 1.8, 1.8);

SetWingAspect (0.7);

SetWingEffectiveness (2.5);

SetCrossSections (_V(10.5,15.0,5.8));

SetRotDrag (_V(0.6,0.6,0.35));

SetPMI (_V(131.19,156.2,31.43));

SetTrimScale (0.05);

SetCameraOffset (_V(0,0.0,5.0));

SetDockParams (_V(0,0,-20.5), _V(0,0,-1), _V(0,0,-1));

SetTouchdownPoints (_V(0,-20,-20.5), _V(-10,20,-20.5), _V(10,20,-20.5));



Ok, you will notice that the landing points above are for a tail-lander ship. Use the equivelant numbers from the Delta Glider ini, or ShuttlePB.cpp example in the SDK if you need help with landing points on air-plane-like ship.


Now we are going to put in some important performance variables. In this section of Type Three code, we will give names and values to things that Orbiter will be looking for.



1. FUELMASS - Just a name or “handle” we are using to define a number that will be used by several other functions (different thrusters) to determine how much fuel the tank we will later create will hold.

Paste and modify the following code to your .cpp.



const double FUELMASS = 5500.0;



In this example it can be seen that I am using the FUELMASS constant for both main engines and rcs thrusters, thus the red and green colors.



2. ISP – Just like for Config files, we are telling the ship a number to use for the efficiency of the engine. This number is being defined as a name for use later. I am defining the number as a name called “ISP”. It could be called anything though.


const double ISP = 6.25e8;




3. MAXMAINTHRUST, MAXRCSTHRUST, - Here we have two more of those constants defined. The names help us remember what thruster definitions they will go into, and they are defined here as constants so that Orbiter is told to remember what these values are all the time.



const double MAXMAINTH = 5.5e6;

const double MAXRCSTH = 1e6;




All right! Now those pesky constants are out of the way we can get on to creating the ship.

We made a constant earlier that has a value for the ship's Fuel Mass. Now we are gonna define a tank to put it in.


PROPELLANT_HANDLE tank;

tank = CreatePropellantResource (FUELMASS);



Cool Beans, this is fun...I hope we havn't screwed anything up yet!

Lets define the thruster handles. Here we have defined handles for one main virtual thruster, 14 RCS, and 4 groups of rcs thrusters. Paste and modify this into your .cpp. The numbers in brackets after the RCS handle means that 14 different thrusters will be named, starting with th_rcs [0] and ending with th_rcs[13]. Most number sets like that start with 0 instead of 1. th_group are the groups of RCS thrusters that are temporarily re-named when they are part of various thruster groups. RCS thrusters are complex, but you don't really need to do a lot of modifications to this code to make your ships work. Just drop it in if you like.


THRUSTER_HANDLE th_main, th_rcs[14], th_group[4];




On to creating the thrusters. You will have some work to do here, but you wil see that when a thruster is created, all the variables it needs are called by the handles we have created beforehand, which you can now identify. For now, only the numbers in this section should be modified, later we will prctice using our own names for things. The Vector 3's for the Main Engine locations or thrust directions are the only thing you really might want to modify. You can mostly just leave the RCS thruster definitions alone. They come directly from the PB shuttle code, with only those two variables modified. You should modify the exhaust emmission points (AddExhaust)to suit your ship. There are two listed here for a two-engine ship, but you an delete one or add more if you like.




th_main = CreateThruster (_V(0,0,-20.5), _V(0,0,1), MAXMAINTH, tank,ISP);

CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);

AddExhaust (th_main, 8, 1, _V(20,0,-18.3), _V(0,0,-1));

AddExhaust (th_main, 8, 1, _V(-20,0,-18.3), _V(0,0,-1));



th_rcs[ 0] = CreateThruster (_V( 1,0, 3), _V(0,1,0), MAXRCSTH, tank , ISP);

th_rcs[ 1] = CreateThruster (_V( 1,0, 3), _V(0,-1,0), MAXRCSTH, tank, ISP);

th_rcs[ 2] = CreateThruster (_V(-1,0, 3), _V(0,1,0), MAXRCSTH,tank, ISP);

th_rcs[ 3] = CreateThruster (_V(-1,0, 3), _V(0,-1,0), MAXRCSTH, tank, ISP);

th_rcs[ 4] = CreateThruster (_V( 1,0,-3), _V(0,1,0), MAXRCSTH, tank, ISP);

th_rcs[ 5] = CreateThruster (_V( 1,0,-3), _V(0,-1,0), MAXRCSTH, tank, ISP);

th_rcs[ 6] = CreateThruster (_V(-1,0,-3), _V(0,1,0), MAXRCSTH, tank, ISP);

th_rcs[ 7] = CreateThruster (_V(-1,0,-3), _V(0,-1,0), MAXRCSTH,tank , ISP);

th_rcs[ 8] = CreateThruster (_V( 1,0, 3), _V(-1,0,0), MAXRCSTH, tank, ISP);

th_rcs[ 9] = CreateThruster (_V(-1,0, 3), _V(1,0,0), MAXRCSTH, tank, ISP);

th_rcs[10] = CreateThruster (_V( 1,0,-3), _V(-1,0,0), MAXRCSTH, tank, ISP);

th_rcs[11] = CreateThruster (_V(-1,0,-3), _V(1,0,0), MAXRCSTH, tank, ISP);

th_rcs[12] = CreateThruster (_V( 0,0,-3), _V(0,0,1), MAXRCSTH, tank, ISP);

th_rcs[13] = CreateThruster (_V( 0,0, 3), _V(0,0,-1), MAXRCSTH, tank, ISP);


th_group[0] = th_rcs[0];

th_group[1] = th_rcs[2];

th_group[2] = th_rcs[5];

th_group[3] = th_rcs[7];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);


th_group[0] = th_rcs[1];

th_group[1] = th_rcs[3];

th_group[2] = th_rcs[4];

th_group[3] = th_rcs[6];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);


th_group[0] = th_rcs[0];

th_group[1] = th_rcs[4];

th_group[2] = th_rcs[3];

th_group[3] = th_rcs[7];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKLEFT);


th_group[0] = th_rcs[1];

th_group[1] = th_rcs[5];

th_group[2] = th_rcs[2];

th_group[3] = th_rcs[6];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKRIGHT);


th_group[0] = th_rcs[0];

th_group[1] = th_rcs[4];

th_group[2] = th_rcs[2];

th_group[3] = th_rcs[6];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_UP);


th_group[0] = th_rcs[1];

th_group[1] = th_rcs[5];

th_group[2] = th_rcs[3];

th_group[3] = th_rcs[7];

CreateThrusterGroup (th_group, 4, THGROUP_ATT_DOWN);


th_group[0] = th_rcs[8];

th_group[1] = th_rcs[11];

CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);


th_group[0] = th_rcs[9];

th_group[1] = th_rcs[10];

CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);


th_group[0] = th_rcs[8];

th_group[1] = th_rcs[10];

CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);


th_group[0] = th_rcs[9];

th_group[1] = th_rcs[11];

CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);


CreateThrusterGroup (th_rcs+12, 1, THGROUP_ATT_FORWARD);

CreateThrusterGroup (th_rcs+13, 1, THGROUP_ATT_BACK);



Done yet? Ok, just one more bit to go! Let's tell the module about our mesh file for the ship, and initialize the ship, then give it the ability to end. Paste and modify this into your .cpp:



AddMesh ("BigRocket1");

}


DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)

{

return new STARSHIP (hvessel, flightmodel);

}


DLLCLBK void ovcExit (VESSEL *vessel)

{

if (vessel) delete (STARSHIP*)vessel;

}



OK fool, moment of truth here. If you have your .cpp file in the editor, and a build .dll tool all ready to go, and have perhaps already compiled a .cpp from the samples, it is time to drop that .cpp into a file next to the orbiter.rsp file you made and compile this thing...stand back!


If you can't compile a file, as you have not gotten a compiler going, I am willing to make a few files for you. Just send me the .cpp files to Masthead@tampabay.rr.com and I will try to hook you up!