C++ Question Structure of C++ code for orbiter

J_Aerospace

New member
Joined
Mar 21, 2008
Messages
53
Reaction score
0
Points
0
Hi First of all i am not really a newbie to c++ but i how ever cannot make head nor tale of the structure regarding the code for makeing plugins etc...
I have read many tutorials but they do not (in my mind) relate to a standard c++ program. Does anyone have any pointers. I would like to build some mfd's or standalone programs that call variables from the main orbiter program e.g speed alt etc...

Thanks
 

computerex

Addon Developer
Addon Developer
Joined
Oct 16, 2007
Messages
1,282
Reaction score
17
Points
0
Location
Florida
Orbiter plug-ins are dlls, or dynamic link library. Dlls contain a bunch of functions that other programs can import and use. That's what Orbiter does, it loads your plug-in dll, imports the callback functions inside of it, and then it calls them approprietely. A dll won't be your typical C++ program..It's a collection of functions. Here's a simple Orbiter module:

Code:
#define STRICT
#define ORBITER_MODULE 

#include <orbitersdk.h>

DLLCLBK void opcPreStep(double simt, double simdt, double mjd)
{
      sprintf(oapiDebugString(), "Simulation time: %.2f minutes", simt/60);
}

This will simply print the simulation time in minutes every frame on the lower left hand corner. Orbiter imports the opcPreStep (notice the dllclbk, for exporting the function) and calls it every time step. I hope that helps. For further help, look at the SDK samples.
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
Hi First of all i am not really a newbie to c++ but i how ever cannot make head nor tale of the structure regarding the code for makeing plugins etc...
I have read many tutorials but they do not (in my mind) relate to a standard c++ program. Does anyone have any pointers. I would like to build some mfd's or standalone programs that call variables from the main orbiter program e.g speed alt etc...

Thanks
Addins aren't a "standard C++ program" - they are all DLLs, ie, libraries. All that a DLL does is provide an executable program with a set of library functions/data that the executable (in this case, Orbiter) can call. They are similar to .lib files except they are linked to the executable at runtime, rather than at compiletime. Orbiter will then call functions from the DLL that you provide (ie, MFD calls and a few other ones OCPPreStep and OCPPostStep from memory I think) to make your DLL do things. You can get information back from orbiter (vessel speed, alt etc) via the API calls. There are tutorials in the tutorial section of the forum that cover development of addons
 

Notebook

Addon Developer
Addon Developer
News Reporter
Donator
Joined
Nov 20, 2007
Messages
11,816
Reaction score
641
Points
188
A question just to show my level of C++...

If I make the module in Computerex example above, and activate it in Orbiter Launchpad and it works fine.
Then J Aerospace makes a module using the same
"DLLCLBK void opcPreStep(double simt, double simdt, double mjd)" but with different code inside the braces, and I activate that module in Launchpad, so both modules/dlls are running.

How does Orbiter handle the same DLLCLBK with different code inside the function/call?

Thanks, N.
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
A question just to show my level of C++...

If I make the module in Computerex example above, and activate it in Orbiter Launchpad and it works fine.
Then J Aerospace makes a module using the same
"DLLCLBK void opcPreStep(double simt, double simdt, double mjd)" but with different code inside the braces, and I activate that module in Launchpad, so both modules/dlls are running.

How does Orbiter handle the same DLLCLBK with different code inside the function/call?

Thanks, N.
When orbiter starts, it loads in the DLLs and searches through them for various functions, one of these functions is opcPreStep. If it can find it, then it adds a function pointer to this function to an internal list. It does this for all the DLLs that are activated in the launchpad. Then, at the start of every timestep, it cycles through all its pointers to the various opcPreSteps found in its DLLs and calls them one at a time in order.

Although different DLLs have the same function name and prototype, this does not matter as the executable just treats them as addresses in memory
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
How does Orbiter handle the same DLLCLBK with different code inside the function/call?
I have to preface this by saying I have never done this, only read about it.

It loads each DLL into memory in turn, then finds and stores pointers to its exported (ie, DLLCLBK) functions. Despite the functions having the same name, they are stored in different locations in memory and can be called individually through the function pointers. The actual name of the function is only used to find its address in memory, not to call the function.

See this document (Case 2) for an example of doing it for a single DLL. The same procedure is used for multiple DLLs except you would use an array, or perhaps a std::vector, to store the function pointers.

EDIT: OK, I obviously type too slow, but at least agentgonzo and I are saying the same thing ;)
 

Notebook

Addon Developer
Addon Developer
News Reporter
Donator
Joined
Nov 20, 2007
Messages
11,816
Reaction score
641
Points
188
Thanks for that agentgonzo, that I can understand.
In a sense, Orbiter dosen't care about the different code inside "my DLLCLBKopcPreStep" or "J Aerospace's DLLCLBKopcPreStep". Both get executed by Orbiter?

Another question!
As I understand it, the Orbiter API functions are in the OrbiterAPI.h are available for me to call from my .dll and use the reurned value/s?

How would I use this for example?

OAPIFUNC double oapiGetEmptyMass (OBJHANDLE hVessel);

Where does the EmptyMass value return to?

N.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
OAPIFUNC double oapiGetEmptyMass (OBJHANDLE hVessel);

Where does the EmptyMass value return to?
The usage would be like:

Code:
OBJHANDLE hV; // handle to vessel, needs to be initialised with a meaningful
    // value before using, eg, by oapiGetVesselByIndex or some callback argument

double emptyMass;
emptyMass = oapiGetEmptyMass(hV);
By declaring emptyMass a space is allocated in memory for you. When oapiGetEmptyMass is called, its return value is pushed (copied) into that memory space.
 

Notebook

Addon Developer
Addon Developer
News Reporter
Donator
Joined
Nov 20, 2007
Messages
11,816
Reaction score
641
Points
188
Thanks tblaxland, makes sense from my limited C++ use.

If I get the broad difference between DLLCLBK and OrbiterAPI.

OrbiterAPI exist in the Orbiter core for me to use from code in my.dll, DLLCLBK (something) exists in the Orbiter core, but is empty, and I can write code in my.dll which will be used?

N.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
OrbiterAPI exist in the Orbiter core for me to use from code in my.dll, DLLCLBK (something) exists in the Orbiter core, but is empty, and I can write code in my.dll which will be used?
Broadly speaking, yes.

The DLL callbacks functions do not actually exist in the Orbiter core. The Orbiter core has simply has ways of finding them in your DLL and using them.

OAPIFUNC's do exist in the Orbiter core and your application knows how to find and use them by way of the orbiter.lib that you link with when building your DLL.

Clear as mud?
 

Scrooge McDuck

Addon Developer
Addon Developer
Joined
Mar 18, 2008
Messages
515
Reaction score
30
Points
28
Location
The Netherlands
Website
orbitermap.no-ip.org
To add:

You could use those Orbiter API functions everywhere in your own DLL code.
But there are some things in your code that you want to be 'triggered' by Orbiter. Certain events like the moment before/after timesteps, initialization, vessel creation, vessel focus changes, keyboard activity, etc. That's what these callbacks are for. It's up to you (the programmer) to choose what callbacks you want to make use of.

This is also explained on page 4 and 5 of API_Reference.pdf (Chapter 6, Concept), worth reading.
 

Notebook

Addon Developer
Addon Developer
News Reporter
Donator
Joined
Nov 20, 2007
Messages
11,816
Reaction score
641
Points
188
Thanks both, that all makes sense.

N.
 

cjp

Addon Developer
Addon Developer
Donator
Joined
Feb 7, 2008
Messages
856
Reaction score
0
Points
0
Location
West coast of Eurasia
If I get the broad difference between DLLCLBK and OrbiterAPI.

OrbiterAPI exist in the Orbiter core for me to use from code in my.dll, DLLCLBK (something) exists in the Orbiter core, but is empty, and I can write code in my.dll which will be used?
Not entirely correct. You're right on OrbiterAPI: there are a lot of functions in the Orbiter core (orbiter.exe) which can be called from your DLL. oapiGetEmptyMass is an example. But the truth on DLLCLBK is a bit different, and maybe that's exactly what confuses you.

DLLCLBK itself is just a preprocessor macro (I guess it is defined somewhere in the Orbiter SDK header files). An example of how to use it is:
Code:
DLLCLBK void opcPreStep(double simt, double simdt, double mjd)
{
      sprintf(oapiDebugString(), "Simulation time: %.2f minutes", simt/60);
}
So, it adds some flags to your function definition (or maybe it does nothing, if DLLCLBK is an empty macro). But most probably it exactly defines the calling convention, which is a convention of how a function should be called on the machine code level. Normally, you as a C/C++ programmer don't need to worry about this, but here it could cause problems if your code is compiled with a different compiler than orbiter.exe, or even with different settings. To avoid all the trouble, you add DLLCLBK to your function prototype. This makes your function's calling convention exactly how Orbiter expects it.
In other words: you need to use DLLCLBK on all functions that need to be called by Orbiter.

That is the meaning of the word DLLCLBK. Now, it is not the case that "(something) exists in the Orbiter core, but is empty, and I can write code in my.dll which will be used". It works differently, and this is also why it's no problem for Orbiter to load multiple DLLs which contain the same function.

You know function pointers? If not, please learn about them before continue reading this. The idea is that Orbiter, for every DLL it loads, it remembers some data, e.g. in a struct or a class (and there probably is an array containing all the DLL data as objects). For instance, Orbiter could remember the name of each DLL it loads. But, more importantly, it remembers some function pointers.

Initially, these function pointers point to nothing (e.g. they could be NULL). But when Orbiter continues loading the DLL, it uses some windows system calls to scan the DLL for certain function names. Windows has a function that accepts a DLL handle, the name of a function as a string, and returns a pointer to that function. So, in each DLL, Orbiter searches for function names like "opcPreStep", and it remembers them as function pointers. Then, whenever these functions need to be called, Orbiter uses these function pointers to call these functions within each DLL.

Was this too complicated / confusing?
 

Notebook

Addon Developer
Addon Developer
News Reporter
Donator
Joined
Nov 20, 2007
Messages
11,816
Reaction score
641
Points
188
Thanks for that also cjp, its complex but not confusing.

Time for a read of the SDK docs(again).

N.
 

Erupter

New member
Joined
Jan 3, 2009
Messages
51
Reaction score
0
Points
0
Location
Rome
But most probably it exactly defines the calling convention, which is a convention of how a function should be called on the machine code level.

cut

In other words: you need to use DLLCLBK on all functions that need to be called by Orbiter.

mmm
but then all that Orbiter could provide would be some pre-defined moments at which to call custom-functions, or pre-defined names for custom-functions to be called.
Otherwise there would be no way of knowing when to call a totally custom func.
Am i right?
 

escapetomsfate

OBSP Developer
Addon Developer
Joined
Jun 21, 2008
Messages
282
Reaction score
0
Points
0
Location
GB
What compiler do you guys use? Im using dev++ for my first MFD. I've added the libraries and headers for the SDK, and tried to compile that sample code given at the start of this thread. All I got was several errors and loads of warnings. Anyone know how to fix this?
 

cjp

Addon Developer
Addon Developer
Donator
Joined
Feb 7, 2008
Messages
856
Reaction score
0
Points
0
Location
West coast of Eurasia
mmm
but then all that Orbiter could provide would be some pre-defined moments at which to call custom-functions, or pre-defined names for custom-functions to be called.
Otherwise there would be no way of knowing when to call a totally custom func.
Am i right?

Your reasoning is correct, but of course your custom function with the name defined by Orbiter (let's say 'pre-defined custom function', e.g. your version of opcPreStep) can then call your own 'totally custom' functions. So, indirectly, you can make all your functions called by the Orbiter process.

And there is another way: when one of these 'pre-defined custom' functions gives Orbiter a new set of function pointers, e.g. in its return value. This is for instance the case when you return a pointer to a VESSEL2-derived object, with your own overloaded virtual functions. Virtual functions are very much like function pointers in terms of what you can do with them. Orbiter is then able to call those other functions too, because it has the function pointers to them (or a pointer to an object of a derived class with overloaded virtual functions).

But the 'first contact' between Orbiter.exe and the DLL has to be through an ordinary function with a pre-defined name.
 

computerex

Addon Developer
Addon Developer
Joined
Oct 16, 2007
Messages
1,282
Reaction score
17
Points
0
Location
Florida
What compiler do you guys use? Im using dev++ for my first MFD. I've added the libraries and headers for the SDK, and tried to compile that sample code given at the start of this thread. All I got was several errors and loads of warnings. Anyone know how to fix this?

The libraries inside OrbiterSDK are specific to Microsoft's VC++ compiler series. I personally use VC++ 2008 express edition.
 
Top