Well, I ran into a snag with VesselMass. ShiftCG( ) does quite a bit of the work I want, moving engines, meshes, viewpoints, etc. Airfoils can be done with EditAirfoil, and touchdown points with SetTouchdownPoints. With enough bookkeeping info, I can slide these things around myself (but it should really be a part of ShiftCG).
Now my problem is that I have some control surfaces on the tail of my rocket. They don't seem to move with ShiftCG, and there is no EditControlSurface similar to EditAirfoil.
A warning for what follows: Professional driver on closed course. Please do not attempt at home, unless you know what you are doing. I am not responsible if following these steps does anything or nothing, including make demons fly out of your nose. I learned about this by reading some code Mavericktech wrote some time ago for Orbiter 2005 to get information not then available through the API.
First off: Many things in the Orbiter API are accessed with HANDLEs. A handle is like a claim check for your dry-cleaning. It doesn't mean anything to you, but it has everything the dry cleaners need to find your clothes.
Likewise with handles. Whenever you create a thruster, propellant resource, or lots of other things, the API gives you a handle. Later when you want to inspect or modify that thing, you give the handle back to the API. It doesn't matter what the handle is. You don't have to interpret it, or really even know what its real type is, because these things are hidden behind the XXXHANDLE type. The API knows how to look up the thing you want from the handle.
Well, as it happens, in a lot of cases, the handle is a pointer to an internal Orbiter structure.
What can we do with this knowledge? Well, we can cast the handle to a pointer and see what it points at. You can do this in your module, or you can use debugging, which is worthwhile enough for an aside on the VC++ debugger. You are using VC++2008 to code, right?
First, compile your program in Debug configuration. To do this, switch the dropdown on the toolbar from Release to Debug. Once you do so, you may also have to change the project properties to get it to compile again, like you did to get Release working.
Now start up Orbiter in Window mode (I have had no luck with full screen mode doing this), then use Debug/Attach to Process to attach to Orbiter.exe. Set some breakpoints in your code by clicking in the left margin to get a big red dot on the line you want to stop at. Then pick a scenario which excercises your addon, and push the Launch button in Orbiter. When the program reaches your breakpoint, VC++ will pop back up, and you can do all the traditional debugging stuff.
One of the things you can do is inspect memory. Figure out what handle you want to look at, then type that into the Memory tab. You can display memory as bytes, hexadecimal, integers, strings, but for Orbiter, it is most often useful to look at it as double-precision floating points.
For concreteness, let's say we are examining a thruster. A thruster has an attack point, direction, maximum thrust, and lots of other stats and goodies. You know what all the parameters are, since you set them yourself at the CreateThruster( ) call. So, you can see what values are where in memory.
Now this isn't really necessary for thrusters, I think, since all thruster parameters are exposed through the API. But the same thing applies to control surfaces, which don't have nearly as complete of an API. PS. Martin: I could use an EditControlSurface( ) function like the EditAirfoil( ) function.
So, you can read parameters right from the source. Cast the handle to a pointer, add the right offset, then read that pointer.
To really have an adventure, try writing to that pointer. If Orbiter works like I expect (hope) it does, you should be able to change any parameter, even without the appropriate API.
Of course, this depends on the details of Martin's source code, which he has chosen to keep to himself. He may change these structures at any time, and this hack would no longer work. That is why you see addons which claim compatibility with a particular Orbiter version ONLY. There is no guarantee that the structures we are poking around with will still be the same, or even be present, in the next version.
So, nitty gritty details. Cast the control surface handle to a double*, say cs for concreteness. Now we have
index cs[j]|meaning
0|Unknown, probably not a double at all
1|attack.x
2|attack.y
3|attack.z
4|Probably not a double
5|Control surface area
6|DeltaCland we can write a new function mimicking the Orbiter api, which uses all this information and does our edits
And this even seems to work!
Now my problem is that I have some control surfaces on the tail of my rocket. They don't seem to move with ShiftCG, and there is no EditControlSurface similar to EditAirfoil.
A warning for what follows: Professional driver on closed course. Please do not attempt at home, unless you know what you are doing. I am not responsible if following these steps does anything or nothing, including make demons fly out of your nose. I learned about this by reading some code Mavericktech wrote some time ago for Orbiter 2005 to get information not then available through the API.
First off: Many things in the Orbiter API are accessed with HANDLEs. A handle is like a claim check for your dry-cleaning. It doesn't mean anything to you, but it has everything the dry cleaners need to find your clothes.
Likewise with handles. Whenever you create a thruster, propellant resource, or lots of other things, the API gives you a handle. Later when you want to inspect or modify that thing, you give the handle back to the API. It doesn't matter what the handle is. You don't have to interpret it, or really even know what its real type is, because these things are hidden behind the XXXHANDLE type. The API knows how to look up the thing you want from the handle.
Well, as it happens, in a lot of cases, the handle is a pointer to an internal Orbiter structure.
What can we do with this knowledge? Well, we can cast the handle to a pointer and see what it points at. You can do this in your module, or you can use debugging, which is worthwhile enough for an aside on the VC++ debugger. You are using VC++2008 to code, right?
First, compile your program in Debug configuration. To do this, switch the dropdown on the toolbar from Release to Debug. Once you do so, you may also have to change the project properties to get it to compile again, like you did to get Release working.
Now start up Orbiter in Window mode (I have had no luck with full screen mode doing this), then use Debug/Attach to Process to attach to Orbiter.exe. Set some breakpoints in your code by clicking in the left margin to get a big red dot on the line you want to stop at. Then pick a scenario which excercises your addon, and push the Launch button in Orbiter. When the program reaches your breakpoint, VC++ will pop back up, and you can do all the traditional debugging stuff.
One of the things you can do is inspect memory. Figure out what handle you want to look at, then type that into the Memory tab. You can display memory as bytes, hexadecimal, integers, strings, but for Orbiter, it is most often useful to look at it as double-precision floating points.
For concreteness, let's say we are examining a thruster. A thruster has an attack point, direction, maximum thrust, and lots of other stats and goodies. You know what all the parameters are, since you set them yourself at the CreateThruster( ) call. So, you can see what values are where in memory.
Now this isn't really necessary for thrusters, I think, since all thruster parameters are exposed through the API. But the same thing applies to control surfaces, which don't have nearly as complete of an API. PS. Martin: I could use an EditControlSurface( ) function like the EditAirfoil( ) function.
So, you can read parameters right from the source. Cast the handle to a pointer, add the right offset, then read that pointer.
To really have an adventure, try writing to that pointer. If Orbiter works like I expect (hope) it does, you should be able to change any parameter, even without the appropriate API.
Of course, this depends on the details of Martin's source code, which he has chosen to keep to himself. He may change these structures at any time, and this hack would no longer work. That is why you see addons which claim compatibility with a particular Orbiter version ONLY. There is no guarantee that the structures we are poking around with will still be the same, or even be present, in the next version.
So, nitty gritty details. Cast the control surface handle to a double*, say cs for concreteness. Now we have
0|Unknown, probably not a double at all
1|attack.x
2|attack.y
3|attack.z
4|Probably not a double
5|Control surface area
6|DeltaCl
Code:
void kapiEditControlSurface(CTRLSURFHANDLE cs, int bits, VECTOR3 &ref, double area, double dCl) {
double* p=(double*)cs;
if(bits & 0x01) {
p[1]=ref.x;
p[2]=ref.y;
p[3]=ref.z;
}
if(bits & 0x02) {
p[5]=area;
}
if(bits & 0x04) {
p[6]=dCl;
}
}
And this even seems to work!