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:
 
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?
 
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.
 
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:
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.
 
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:
 
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.
 
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.
 
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...:)
 
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.
 
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:
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.
 
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:
 
Back
Top