Project Blue Streak F3(DLL)

Put two new cases for the 'C' and 'V' keys. 'C' for engines cut-off and 'V' for vectoring. The 'C' works fine, and cuts-off the mains, the 'V' is working, but not giving results I expected...there's a surprise.

Code:
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]
int[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] BlueStreak::clbkConsumeBufferedKey (DWORD key, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]bool[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] down,[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]char[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] *kstate)
{
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]if[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (!down) [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 0; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//only process keydown events
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]if[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (!KEYMOD_SHIFT (kstate))
{ [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// unmodified keys
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]switch[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (key)
{ [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_L: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Fire mains
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]SetThrusterLevel(th_Pack[0], 1);
SetThrusterLevel(th_Pack[1], 1);
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_C: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Cut-off Mains
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]SetThrusterLevel(th_Pack[0], 0);
SetThrusterLevel(th_Pack[1], 0);
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_V: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Vector Mains
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]
SetThrusterDir(th_main, _V(0,0,-15000));
[/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//thDir = (_V(127,126,125));
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2];[/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;
}
}
[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 0;
}
[/SIZE]

This is the state just after lift off:-

http://i89.photobucket.com/albums/k207/Notebook_04/09062309-51-03PB-01.jpg

I then put the negative value (-15000)into the 'z' element of thDir with the 'V' key, and this shows up in this second run:-

http://i89.photobucket.com/albums/k207/Notebook_04/09062309-51-45PB-01.jpg

However, the direction of thrust is still in the +Z direction, I was expecting it to reverse to the -Z, after the 'V' key-press?

All input appreciated!

N.
 
Yes, direction vectors in Orbiter need to be of magnitude 1.0 - meaning they have to be normalized. You give a non-normalized vector into SetThrusterDir, which expects a normalized direction vector.
 
Thanks Urwumpe, I'll give that a go.

N.

---------- Post added at 10:53 ---------- Previous post was at 10:37 ----------

As a secondary question...what am I getting back from
GetThrusterDir(th_main, thDir);

The debug string shows "0.0, 0.0, 15000". This isn't normalised? Is it Orbiters internal values, and not relevant to what I need?

thanks, N.

 
The debug string shows "0.0, 0.0, 15000". This isn't normalised? Is it Orbiters internal values, and not relevant to what I need?
It indicates that it was not set properly in the first place. Is that result after pressing 'V' or before? If before, what does your CreateThruster look like in clbkSetClassCaps?

EDIT: To clarify what Urwumpe was saying above, to set thrust in the negative direction, you want to do:
Code:
SetThrusterDir(th_main, _V(0,0,-1));
 

The debug string shows "0.0, 0.0, 15000". This isn't normalised? Is it Orbiters internal values, and not relevant to what I need?

The magnitude of a vector is defined as sqrt(x² + y² + z²) (yes, this is Pythagoras). To reach magnitude 1.0, you have to divide each component of the vector by the magnitude of the vector for normalizing it.

in your case the result will be:

Magnitude: sqrt (0.0 + 0.0 + 15000²) = 15000.
Divide components: (0.0/15000 = 0.0; 0.0/15000 = 0.0; 15000/15000 = 1.0)

And done. Orbiter does not check that you use correct inputs, it is garbage in - garbage out (or garbage in - crash out)
 
The OrbiterSDK also provides some handy undocumented functions and overloaded operators to help you with VECTOR3 operations. For example:
Code:
VECTOR3 someVec = _V(1,2,3);
someVec /= length(someVec); // someVec is now normalised
 
Just to check I'm on the right track. This is the latest "clbkConsumeBufferedKey " state.

Code:
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] BlueStreak::clbkConsumeBufferedKey (DWORD key, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]bool[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] down,[/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]char[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] *kstate)[/SIZE]
[SIZE=2]{[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]      if[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (!down) [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 0; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//only process keydown events[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]      if[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (!KEYMOD_SHIFT (kstate))[/SIZE]
[SIZE=2]         { [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// unmodified keys[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]             switch[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] (key){[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]     case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_L: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Fire mains[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]SetThrusterLevel(th_Pack[0], 1);[/SIZE]
[SIZE=2]SetThrusterLevel(th_Pack[1], 1);[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]     return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]     case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_C: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Cut-off Mains[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]SetThrusterLevel(th_Pack[0], 0);[/SIZE]
[SIZE=2]SetThrusterLevel(th_Pack[1], 0);[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]     return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//RZ_2 engine maximum gimbal 7 degrees. [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// sin(7 degrees) = 0.122, cos(7 degrees) = 0.993.[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//VECTOR3 someVec = _V(1,2,3);[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//someVec /= length(someVec); // someVec is now normalised[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//VECTOR3 someVec = _V(0,0.993,0.878);[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//someVec /= length(someVec);[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//oapiGetFocusAltitude(&blueStreakAltitude);[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//oapiGetFocusHeading(&blueStreakHeading);[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//blueStreakHeading = blueStreakHeading*180/PI;// convert to degrees[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Normalised Max Pitch = (0, 0.749, 0.663)[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]      case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_NUMPAD4: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Vector Mains: Roll Left [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]       {[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[0], (_V(0, 0.749, 0.663)));[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[1], (_V(0,-0.749, 0.663)));[/SIZE]
[SIZE=2]        }[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_NUMPAD6: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Roll Right: [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]        {[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[0], (_V(0,-0.749, 0.663)));[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[1], (_V(0, 0.749, 0.663)));[/SIZE]
[SIZE=2]         }[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_NUMPAD5: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Centre Mains: [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]        {[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[0], (_V(0,0,1)));[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[1], (_V(0,0,1)));[/SIZE]
[SIZE=2]         }[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]         return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]         case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_NUMPAD8: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Pitch Down: [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]        {[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[0], (_V(0, 0.749, 0.663)));[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[1], (_V(0, 0.749, 0.663)));[/SIZE]
[SIZE=2]          }[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]         return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]         case[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] OAPI_KEY_NUMPAD2: [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// Pitch Up: [/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]         {[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[0], (_V(0, -0.749, 0.663)));[/SIZE]
[SIZE=2]SetThrusterDir(th_Pack[1], (_V(0, -0.749, 0.663)));[/SIZE]
[SIZE=2]          }[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]          return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 1;[/SIZE]
[SIZE=2]    }[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]return[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] 0;[/SIZE]
[SIZE=2]}[/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Closing brace of clbkConsumeBufferedKey[/COLOR][/SIZE]
[/COLOR][/SIZE]

I moved the BlueStreak class definition into a BlueStreak.h file, along with the "Some Vessel Paramaters" code, and the "LiftCoeff" function.
That was fairly painless, and seemed to work ok.

Couldn't get th_main to give .x, .y, .z return values, so using the th_Pack[] array, and that displays in the debug string ok.

The thing I would like to confirm is getting the vector3 values for gimbleing the individual engines, Pack[0], and Pack[1].

Have a value of 7 degrees maximum angle for the RZ_2 engine, so took the sine and cos of this, subtracted from 1 to give this vector3 _V(0,0.993,0.878).
Normalised this as your replies above, giving vector3 _V(0, 0.749, 0.663)
Then changed the sign of the .y value depending what direction was needed.
This works, though the pitch is a bit fierce!
Anything obviously wrong so far?

Many thanks, N.
 
Last edited:
Just starting on the engines gimble animation, and having a bit of trouble.

This is the class constructor in the .h file

Code:
// --------------------------------------------------------------
// Set the capabilities of the vessel class
// --------------------------------------------------------------
class BlueStreak: public VESSEL2 {
public:
    BlueStreak (OBJHANDLE hVessel, int flightmodel)
    : VESSEL2 (hVessel, flightmodel) {}
    void clbkSetClassCaps (FILEHANDLE cfg);
    void clbkPreStep(double SimT, double SimDT, double Mjd);
    int clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
    THRUSTER_HANDLE th_main,th_Pack[2];
    VECTOR3 thDirPackA, thDirPackB, someVec ;
    double blueStreakHeading;
    double blueStreakAltitude;
 
    void DefineAnimations();
 
}; //Closing brace of class interface

As soon as I put the DefineAnimations in the .cpp file I get this error
>BlueStreak.obj : error LNK2001: unresolved external symbol "public: void __thiscall BlueStreak::DefineAnimations(void)" (?DefineAnimations@BlueStreak@@QAEXXZ)
1>..\..\..\Orbiter_060929\Modules\ShuttlePB.dll : fatal error LNK1120: 1 unresolved externals

This confusing because as soon as I type the "BlueStreak::" I get the available functions list, and DefineAnimations() is one of those?

All input appreciated.

N.
 
Just starting on the engines gimble animation, and having a bit of trouble.

This is the class constructor in the .h file

Code:
// --------------------------------------------------------------
// Set the capabilities of the vessel class
// --------------------------------------------------------------
class BlueStreak: public VESSEL2 {
public:
    BlueStreak (OBJHANDLE hVessel, int flightmodel)
    : VESSEL2 (hVessel, flightmodel) {}
    void clbkSetClassCaps (FILEHANDLE cfg);
    void clbkPreStep(double SimT, double SimDT, double Mjd);
    int clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
    THRUSTER_HANDLE th_main,th_Pack[2];
    VECTOR3 thDirPackA, thDirPackB, someVec ;
    double blueStreakHeading;
    double blueStreakAltitude;
 
    void DefineAnimations();
 
}; //Closing brace of class interface

As soon as I put the DefineAnimations in the .cpp file I get this error


This confusing because as soon as I type the "BlueStreak::" I get the available functions list, and DefineAnimations() is one of those?

All input appreciated.

N.
Did you define the DefineAnimations() function in the .cpp file as well? If the function is not fleshed out, the code won't know what to do when you call that function.
 
No, I didn't.
I thought I could get away with just putting the function into the BlueStreak class in the .cpp file, and building the animation up from there.
To put in another way, I don't know what I'm doing.

I'll leave this thread as is, till I know a bit more about C++ stuff.

Thanks Hielor,

N.
 
Some help with the terminology:

This is not a class constructor:
Code:
class BlueStreak: public VESSEL2 {
public:
    BlueStreak (OBJHANDLE hVessel, int flightmodel)
    : VESSEL2 (hVessel, flightmodel) {}
    void clbkSetClassCaps (FILEHANDLE cfg);
    void clbkPreStep(double SimT, double SimDT, double Mjd);
    int clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
    THRUSTER_HANDLE th_main,th_Pack[2];
    VECTOR3 thDirPackA, thDirPackB, someVec ;
    double blueStreakHeading;
    double blueStreakAltitude;
 
    void DefineAnimations();
 
};
...it is a class definition. Since not all the member functions are defined (some are only declared), it is an incomplete definition.

This is the constructor:
Code:
    BlueStreak (OBJHANDLE hVessel, int flightmodel)
    : VESSEL2 (hVessel, flightmodel) {}
(the constructor is a special class member function that has the same name as the class and is called automatically when an instance of the class is created)

This a member function declaration:
Code:
    void DefineAnimations();
...and this is a member function definition (my example):
Code:
void BlueStreak::DefineAnimations() { //some code here } //function does nothing
Combined member function declaration/definition:
Code:
class BlueStreak: public VESSEL2 {
public:
//...
    void DefineAnimations() { //some code here };
//...
};
In summary, declarations can also be definitions but you can also declare and define functions separately. Any function that is declared must be also be defined, at least it does if you want to use it. Based on your error above, I would say you have a call to the function BlueStreak::DefineAnimations somewhere in your code.

Some more on the distinction between declarations and definitions:
http://msdn.microsoft.com/en-us/library/0e5kx78b(VS.80).aspx
http://msdn.microsoft.com/en-us/library/0kw7hsf3(VS.80).aspx
http://msdn.microsoft.com/en-us/library/9e2zdck2(VS.80).aspx

EDIT: I had a major toddler-induced posting error there. See corrected post above.
 
Thanks for that tb, clears a few things for me. You are correct about the DefineAnimations, I was trying to build it up from empty brackets, guess I can't do that "on the fly"! Time for a bit more research.

N.
 
Using the example on page 17 of the API_Guide.pdf, and changing some names, I was trying to use the debug string to display some info on the MGROUP_ROTATE_packA class.
I always get a
unresolved external symbol "public: static class MGROUP_ROTATE __cdecl BlueStreak::packA(void)
If I comment out the debug string, it compiles and links ok. I thought this implied the class had been made, and I could access its variables?

This is the .h
Code:
[SIZE=2][COLOR=#0000ff]
[SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] BlueStreak: [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]public[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] VESSEL2 {[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]public[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]:[/SIZE]
[SIZE=2]BlueStreak (OBJHANDLE hVessel, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] flightmodel)[/SIZE]
[SIZE=2]: VESSEL2 (hVessel, flightmodel) {}[/SIZE]
 
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   void[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] clbkSetClassCaps (FILEHANDLE cfg);[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   void[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] clbkPreStep([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]double[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] SimT, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]double[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] SimDT, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]double[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] Mjd);[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   int[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] clbkConsumeBufferedKey (DWORD key, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]bool[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] down, [/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]char[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] *kstate);[/SIZE]
 
 
[SIZE=2]   THRUSTER_HANDLE th_main,th_Pack[2];[/SIZE]
[SIZE=2]   VECTOR3 thDirPackA, thDirPackB ;[/SIZE]
 
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   void[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] DefineAnimations();[/SIZE]
[SIZE=2]   UINT gimbalA;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA();[/SIZE]
 
[SIZE=2]}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Closing brace of class interface[/COLOR][/SIZE]
[/COLOR][/SIZE]

And this is in the .cpp file
Code:
[SIZE=2]} [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//closing brace of BlueStreak class[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] void[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] BlueStreak::DefineAnimations()[/SIZE]
[SIZE=2]   {[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UINT groups[2] = {1, 2}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// participating groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]        static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA [/SIZE]
[SIZE=2]              ([/SIZE]
[SIZE=2]                0, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// mesh index[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]                groups, 1, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// group list and # groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]                _V(0,-1.0,8.5), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation reference point[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]                _V(1,0,0), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation axis[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]               ([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]float[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])(0.5*PI) [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// angular rotation range[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]               );[/SIZE]
[SIZE=2]   gimbalA = CreateAnimation (0.0);[/SIZE]
[SIZE=2]   AddAnimationComponent (gimbalA, 0, 1, &packA);[/SIZE]
[SIZE=2]}[/SIZE]
I thought I was getting close, but obviously(not to me) there is something wrong. Any ideas?

Many thanks, N.
 
Why do you have two groups in the list and say that only one should be used?
 
Good question! I was hoping to start on one pack, keep it simple, then animate the other once I got an idea of the process.
At the minute, the mesh is a place-holder, group 0 is the body, with two cylinders, group1 and group2 to model the engines.

I thought I could give the array "groups[2]" as that, but chose to use any one(or more) in the actual packA class? Is that not allowed?

N.
 
unresolved external symbol "public: static class MGROUP_ROTATE __cdecl BlueStreak::packA(void)
^ That error tells you that you are trying to access a member that is not actually there. You have made two errors:

1. The declaration of BlueStreak::packA is not also a definition. Static members must be defined outside of the class: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.10. If it is not defined, it does not exist.

2. You have declared and defined a another packA MGROUP_ROTATE object in DefineAnimations. This packA object has its scope limited to the DefineAnimations function, but the same object will be accessed by all instances of the BlueStreak class. The problem is that you also want to access the packA object outside of the DefineAnimations function (like in clbkPostStep, for example.

You'll see in something like the default DeltaGlider code that the static MGROUP_xxx objects in DefineAnimations are not accessed outside of that function, they are only used within that function for adding to the animation components. The reason for using the statics in the first place is so that the objects persist in memory after DefineAnimations returns so that the Orbiter core can access them when doing the animations. The other alternative is to have them as non-static member objects but that is not very memory friendly (I have done it though on a project where the objects needed different data in them for each vessel instance, but that would be the exception rather than the rule).

I thought I could give the array "groups[2]" as that, but chose to use any one(or more) in the actual packA class? Is that not allowed?
Yes, but you would do it like this:
Code:
        static MGROUP_ROTATE packA 
              (
                0, // mesh index
                groups, [COLOR=Red][B]2[/B][/COLOR], // group list and # groups
                _V(0,-1.0,8.5), // rotation reference point
                _V(1,0,0), // rotation axis
               (float)(0.5*PI) // angular rotation range
               );
 
I've moved the class MGROUP_ROTATE out of the class interface in .h file:-

Code:
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] void[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] DefineAnimations();[/SIZE]
[SIZE=2] UINT gimbalA;[/SIZE]
[SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//static class MGROUP_ROTATE packA;[/COLOR][/SIZE]
[/COLOR][/SIZE]
[SIZE=2]}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Closing brace of class interface[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2] UINT groups[2] = {1, 2};[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] static [/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA[/SIZE]
[SIZE=2]   ([/SIZE]
[SIZE=2]    0, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// mesh index[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]    groups, 2, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// group list and # groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(0,-1.0,8.5), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation reference point[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(1,0,0), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation axis[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]  ([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]float[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])(0.5*PI) [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// angular rotation range[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]  ); [/SIZE]
and commented out the DefineAnimation call in the .cpp file:-

Code:
[SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//BlueStreak::DefineAnimations()[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//{[/COLOR][/SIZE]
[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UINT groups[2] = {1,2}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// participating groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] static [/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA[/SIZE]
[SIZE=2]  ([/SIZE]
[SIZE=2]    0, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// mesh index[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   groups, 2, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// group list and # groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(0,-1.0,8.5), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation reference point[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]  _V(1,0,0), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation axis[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2] ([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]float[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])(0.5*PI) [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// angular rotation range[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2] );[/SIZE]
 
[SIZE=2] gimbalA = CreateAnimation (0.0);[/SIZE]
[SIZE=2] AddAnimationComponent (gimbalA, 0, 1, &packA);[/SIZE]
[SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//}[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]} [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//closing brace of BlueStreak class[/COLOR][/SIZE]
[/COLOR][/SIZE]
This compiles and links, and when I use this:-

Code:
[SIZE=2]sprintf(oapiDebugString(), [/SIZE][SIZE=2][COLOR=#a31515][SIZE=2][COLOR=#a31515]"SimT %0.1f &packA %x"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] , SimT, &packA);[/SIZE]

I get a 7 digit string for &packA, typically "a83ab88", though it does vary for each run of orbiter.
Can I assume that class MGROUP_ROTATE packA, is now valid, and I can try some DefineAnimations() with it?

Many thanks, N.
 
Last edited:
I've moved the class MGROUP_ROTATE out of the class interface in .h file:-
No, you have misunderstood. If you want* packA to be a member of the BlueStreak class, it needs to be declared inside the class definition and defined outside the class definition.

You would do that like this:
Code:
class BlueStreak: public VESSEL2 {
//...
private:
   static UINT groups[2];
   static MGROUP_ROTATE packA;
//...};

UINT BlueStreak::groups[2] = {1,2};
MGROUP_ROTATE BlueStreak::packA
   (
    0, // mesh index
    groups, 2, // group list and # groups
    _V(0,-1.0,8.5), // rotation reference point
    _V(1,0,0), // rotation axis
    (float)(0.5*PI) // angular rotation range
    );


Some points about this code:
1. The declarations inside the BlueStreak class definition do not define those objects, all they do is let the compiler know what you are going to put there.
2. The objects are actually defined, ie, so the compiler knows what to put in them, after the class definition is closed.
3. groups also needs to be static. This is because although static class members have their scope limited to within the class, the have a lifetime outside of all instances of the class and so cannot contain references to non-static members that could be destroyed when a class instance is deleted. EDIT: some info on scope and lifetime, and the difference between them: http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Scope#Scope_and_lifetime

* Warning: lecture following. You should want it to be a member as you should avoid global variables/class instances if you can. I normally limit myself to one (or two if I'm feeling lazy :P). Globals are not evil per se, but it is often better to limit the scope of any variable to only where it is needed, in this case that is inside the BlueStreak class.
 
Last edited:
Thanks tb, let me digest that, and I'll come back.

N.

---------- Post added 06-07-09 at 10:23 ---------- Previous post was 05-07-09 at 12:17 ----------

Well, I've had a nice Sunday reading about scopes, and lasses, err... classes. and still stuck at this point.
This is the end of the .h file:-

Code:
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]private[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]:[/SIZE]
 
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UINT groups[2];[/SIZE]
 
 
[SIZE=2]}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Closing brace of class interface[/COLOR][/SIZE]
 
[/COLOR][/SIZE]
 
 
[SIZE=2]   UINT groups[2] = {1,2};[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA[/SIZE]
[SIZE=2]   ([/SIZE]
[SIZE=2]   0, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// mesh index[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   groups, 2, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// group list and # groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(0,-1.0,8.5), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation reference point[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(1,0,0), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation axis[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   ([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]float[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])(0.5*PI) [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// angular rotation range[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]  );[/SIZE]
This compiles and links quite happily, dosen't do anything of course...nothing new there.
I tried getting the &packA into sprintf debug, still pretends it unresolved external, so I tried groups[] and groups. This is the current sprintf debug:-
Code:
[SIZE=2]sprintf(oapiDebugString(), [/SIZE][SIZE=2][COLOR=#a31515][SIZE=2][COLOR=#a31515]"SimT %0.1f &groups %x "[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2], SimT, &groups );[/SIZE]
and I get my best friend
Code:
[SIZE=1]1>BlueStreak.obj : error LNK2001: unresolved external symbol "private: static unsigned int * BlueStreak::groups" (?groups@BlueStreak@@0PAIA)[/SIZE]

So, I learned something, MGROUP_ROTATE packA won't be valid unless all its fields are valid? Also compiler error messages sometimes can be missleading.

Don't understand why groups (or groups[], or groups[2], tried them all), isn't valid? I suspect its to do with its scope, but I can't see it.

On another side, I thought arrays started from 0, so groups[2} has three elements; when I tried to fill it with {0,1,2) it got a "too many initialisers" message?

All input appreciated.

N.
 
I tried getting the &packA into sprintf debug, still pretends it unresolved external, so I tried groups[] and groups.
When you refer to a variable name inside a member function, the compiler looks for that variable name from the smallest scope out to the largest scope and links against what it finds first. So, for this code:
Code:
[SIZE=2]sprintf(oapiDebugString(), [/SIZE][SIZE=2][COLOR=#a31515][SIZE=2][COLOR=#a31515]"SimT %0.1f &groups %x "[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2], SimT, &groups );[/SIZE]
the compiler finds BlueStreak::groups declared in the BlueStreak class definition. Because static members have external linkage, the object file gets passed to the linker which then looks for the definition of BlueStreak::groups. It can't find it because you have not written it.

What you have missed (in red bold, compare with my code snippets in my previous post):
Code:
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]private[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]:[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]  static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff] class[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] MGROUP_ROTATE packA;[/SIZE]
[SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]   static[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UINT groups[2];[/SIZE]
[SIZE=2]}; [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]//Closing brace of class interface[/COLOR][/SIZE]
[/COLOR][/SIZE] 
[SIZE=2]UINT [B][COLOR=Red]BlueStreak::[/COLOR][/B]groups[2] = {1,2};[/SIZE]
[SIZE=2]MGROUP_ROTATE [B][COLOR=Red]BlueStreak::[/COLOR][/B]packA[/SIZE]
[SIZE=2]   ([/SIZE]
[SIZE=2]   0, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// mesh index[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   groups, 2, [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// group list and # groups[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(0,-1.0,8.5), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation reference point[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   _V(1,0,0), [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// rotation axis[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]   ([/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff]float[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])(0.5*PI) [/SIZE][SIZE=2][COLOR=#008000][SIZE=2][COLOR=#008000]// angular rotation range[/COLOR][/SIZE]
[/COLOR][/SIZE][SIZE=2]  );[/SIZE]
Without the BlueStreak:: prefix the compiler does not know that those variables are members of the BlueStreak class and it instantiates them as global variables.

So, I learned something, MGROUP_ROTATE packA won't be valid unless all its fields are valid?
The class won't be valid if it is not defined. If you define it, it will be instantiated and be "valid", ie, have a place in memory. That does not prevent its members having rubbish in them though - rubbish in, rubbish out.

Also compiler error messages sometimes can be missleading.
Compiler errors are generally straight-forward. Linker errors often need a little more thought. An understanding of the process helps though. In that regard, I at least recommend reading the wikipedia article to help give you an understanding of what the linker's job is.

On another side, I thought arrays started from 0, so groups[2} has three elements; when I tried to fill it with {0,1,2) it got a "too many initialisers" message?
When declaring an array, the number between the square braces tells the compiler how many elements are in the array. When dereferencing the array declarator (ie, its name), the number in the square braces tells the compiler what element of the array you want. So "UINT groups[2];" tells the compiler you have an array with two elements, the first one being groups[0] and the second groups[1].

EDIT: I found this really good article about statics: Statics: Schizophrenia for C++ Programmers. It might be a bit heavy but if you read it two or three times it should start to make sense :P
 
Last edited:
Back
Top