C++ Question Need a bit of help with vessel cast

slaver0110

Member
Joined
Mar 21, 2011
Messages
72
Reaction score
2
Points
6
I have my orbital tug and class-specific MFD working well; without the help of everyone here it would have been impossible.:thumbup:

However, I'm having trouble with where the vessel-cast should take place.

A little background:
The MFD for the Tug is designed to be class-specific, so that a lot of flags in the vessel can be controlled and monitored from the MFD. This requires the including of the 'Tug1.h' file, and then a simple cast:
Code:
pVessel = static_cast<Tug1*>(v);

Of course, there has to be a checking routine to make sure that the current focus-vessel is of the Tug1 class, because my guess would be that if I changed to another vessel, the TugMFD would try to access the non-Tug vessel and crash Orbiter.
So, I use a simple check of the current focus vessel to make sure it's a Tug:
Code:
bool Tug1MFD::VesselCheck()
{
	hVessel = oapiGetFocusObject();
	v = oapiGetVesselInterface(hVessel);
	sprintf(TestClass, v->GetClassNameA());

	switch (strcmp(TestClass, "Tug1"))
	{
	case 0:
		pVessel = static_cast<Tug1*>(v);
		return true;
	case !0:
		return false;
	default:
		return false;
	}
}
This check works well, and does exactly what I need it to.
The problem is where I currently have the check originating from:
Code:
bool Tug1MFD::Update(oapi::Sketchpad *skp)
{
	Title(skp, "Tug1MFD");
	skp->SetFont(font);
	skp->SetTextColor(0x00FFFF);	

	switch (VesselCheck())
	{
	case true:
		iPodThrust = (float)pVessel->PodThrust * 100;
		len = sprintf_s(buff, TestClass);
		skp->Text(100, 100, buff, len);
		len = sprintf_s(buff, "PodFlag: %.0f", pVessel->PodFlag);
		skp->Text(100, 130, buff, len);
		len = sprintf_s(buff, "PodThrust: %2f", iPodThrust);
		skp->Text(100, 160, buff, len);
		if (CheckTugDock())
		{
			len = sprintf_s(buff, "DOCKED");
			skp->Text(100, 190, buff, len);
		}
		break;
	case false:
		len = sprintf_s(buff, "NOT A TUG");
		skp->Text(100, 100, buff, len);  break;
	}
	return true;
}
The more experienced coders here will immediately see what the problem is...yes, VesselCheck() is being called from the Update method.
While this works, it also means that while the Tug is the current focus, the cast is happening every frame!!!

And that's where I could use some help.:shrug: I've been trying to think of a way to set this up so that once the Tug is the focus vessel, the cast happens once, and if the focus changes to a different vessel class it doesn't happen.

A little handholding in the right direction would be great here. As I said, the code works as-is, but the idea that it's re-casting every frame is one of those things that would cause me to lose sleep.

Cheers, and thanks in advance!!:cheers:
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
As I said, the code works as-is, but the idea that it's re-casting every frame is one of those things that would cause me to lose sleep.

Why? What do you think that casting is?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,625
Reaction score
2,343
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
You do know that it is possible to make vessel-specific MFDs in Orbiter 2016?

Also, casting the vessel is not the big issue there - static_casts happen just inside the compiler. But checking the focus vessel every timestep is. If I remember correctly, a MFD instance is ALWAYS tied to a vessel, the focus vessel is passed to the constructor.
 

slaver0110

Member
Joined
Mar 21, 2011
Messages
72
Reaction score
2
Points
6
But checking the focus vessel every timestep is. If I remember correctly, a MFD instance is ALWAYS tied to a vessel, the focus vessel is passed to the constructor.

Not sure if I'm reading you correctly here.
Are you saying that it's VesselCheck() that only needs to be executed once?

As for the class-specific MFD's in 2016, no I didn't know that.
 
Last edited:

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,625
Reaction score
2,343
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Not sure if I'm reading you correctly here.
Are you saying that it's VesselCheck() that only needs to be executed once?

Yes - when the MFD instance is created.
 

slaver0110

Member
Joined
Mar 21, 2011
Messages
72
Reaction score
2
Points
6
Ah, I see it now.
Ok, reworked it into a method called by the MFD constructor, and it works perfectly.

Thanks for the help.
And Cheers!!!:cheers:
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
While this works, it also means that while the Tug is the current focus, the cast is happening every frame!!!

The cast is not the problem. The string comparison.... eeeeewyeah, that's ugly.
You could use dynamic_cast instead of static_cast and check the returned pointer for null instead, that would be faster.

But I agree with the above suggestions. Keep your vessel pointer around for the lifetime of the MFD.
 

dbeachy1

O-F Administrator
Administrator
Orbiter Contributor
Addon Developer
Donator
Beta Tester
Joined
Jan 14, 2008
Messages
9,218
Reaction score
1,566
Points
203
Location
VA
Website
alteaaerospace.com
Preferred Pronouns
he/him
One thing to note regard casting if it hasn't been spelled out earlier in this thread: with the exception of dynamic_cast, typecasting do not incur any extra runtime overhead at all: it is simply telling the compiler how to "look at" a block of memory. More information is in this StackOverflow thread.

In other words, feel free to use static_cast, const_cast, or reinterpret_cast wherever you need it: they do not incur any extra runtime overhead at all. :thumbup:

P.S. I have never needed to use dynamic_cast anywhere in the XR projects, but I've needed to use each of the three other types (static_cast, const_cast, and reinterpret_cast). None of those add any runtime overhead at all, though.
 

slaver0110

Member
Joined
Mar 21, 2011
Messages
72
Reaction score
2
Points
6
You could use dynamic_cast instead of static_cast and check the returned pointer for null instead, that would be faster.

Already done; switched to a dynamic cast and have everything exactly where I need it.

Code:
bool TestMFD::ValidVessel()
{
	hVessel = oapiGetFocusObject();
	VESSEL *v;
	v = oapiGetVesselInterface(hVessel);
	
	sprintf(TestClass, v->GetClassNameA());
	if (strcmp(TestClass, "Tug1") != 0)
	{
		CurrentView = V_NOCLASS;
		return false;
	}
	else
	{
		T1 = dynamic_cast<Tug1*>((VESSEL3*)v);
		CurrentView = V_ONLINE;
		return true;
	}
}

Just out of curiosity, what's wrong with the string comparison?
Cheers!!:cheers:

---------- Post added at 02:17 PM ---------- Previous post was at 02:11 PM ----------

In other words, feel free to use static_cast, const_cast, or reinterpret_cast wherever you need it: they do not incur any extra runtime overhead at all. :thumbup:

This is exactly what I was originally concerned about. I imagined, due to inexperience, the cast happening every frame.

I'm learning, slowly but surely...:)
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,625
Reaction score
2,343
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
This is exactly what I was originally concerned about. I imagined, due to inexperience, the cast happening every frame.

A cast usually only changes the data type of a pointer or variable. This means it happens either completely at compile time ( C cast, static_cast, reinterpret_cast, const_cast) or have only little overhead (dynamic_cast, out_cast).

It is simply needed for syntactic reasons. If a cast operator would not exist, we would implement one.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
Just out of curiosity, what's wrong with the string comparison?

Strings are arrays. Comparing and/or manipulating them is expensive, and should never be done on a frame by frame basis if it can be avoided.

I have lots of string comparisons in my loading code. But once the first frame ticks in, I avoid them like the plague.
 
Last edited:

jangofett287

Heat shield 'tester'
Joined
Oct 14, 2010
Messages
1,150
Reaction score
13
Points
53
TBF, this use case is basically what dynamic_cast was made for. I'm not sure how expensive the type check is, but it's almost certainly less than a string comparison, even on short strings.
 

slaver0110

Member
Joined
Mar 21, 2011
Messages
72
Reaction score
2
Points
6
Strings are arrays. Comparing and/or manipulating them is expensive, and should never be done on a frame by frame basis if it can be avoided.

Thanks for that, and understood.
I've neatly grouped the string comparison with the ValidVessel method that is called off the MFD constructor, which I understand is only called once.

Again, thanks to everyone for all the help!!
And cheers!!:cheers:
 
Top