C++ Question Animation: Continuous cycle

Dany

Addon-Dev F.O.I.
Joined
Apr 7, 2011
Messages
18
Reaction score
0
Points
0
Hi, I'm programming a new add-on and I need help.
I'm continuing the compilation of "Stand" (my latest add-on) by changing and adding other parameters.
But now I added an animation and works fine, but not as I wish.
The animation I copied from the sample of the DG, I remind you that I am not a programmer, and not finding examples do not know how to do.

Into practice I want the animation to loop continuous and when the key we again press stops.
While now makes a turn and stops. And when I press again the key, go back.
I understood little, but I think should be modified "ActivateInnerAirlock", but how?

To better understand, with "Spacecraft" just add "REPEAT = 1" in the statement of the key.

Here's what I did:

File Cpp.
Code:
#define ORBITER_MODULE
#include "MyVessel.h"

HINSTANCE g_hDLL;


// --------------------------------------------------------------
// Constructor
// --------------------------------------------------------------
MyVessel::MyVessel (OBJHANDLE hObj, int fmodel)
: VESSEL3 (hObj, fmodel)
{
	ilock_status      = DOOR_CLOSED;
	ilock_proc        = 0.0;
	visual            = NULL;
	exmesh            = NULL;

	skinpath[0] = '\0';
    skin        = NULL;

	DefineAnimations();
}

// --------------------------------------------------------------
// Destructor
// --------------------------------------------------------------
MyVessel::~MyVessel ()
{
	if (skin) oapiReleaseTexture (skin);

}



//=========================================================
// Vessel Animations
//=========================================================
void MyVessel::DefineAnimations()
{
	int i;
	// ***** Inner airlock animation *****
	static UINT ILockGrp[23] = {8,9,11,12,13,14,17,18,25,26,29,30,33,34,35,36,43,84,85,87,88,89,90};
	static MGROUP_ROTATE ILock (0, ILockGrp, 23,
		_V(0, 0, 0), _V(0, 0, 1), (float)(-360*RAD));
	
	anim_ilock = CreateAnimation (0);
	AddAnimationComponent (anim_ilock, 0, 1, &ILock);
}

// --------------------------------------------------------------
// Apply custom skin to the current mesh instance
// --------------------------------------------------------------
void MyVessel::ApplySkin ()
{
	if (!exmesh) return;
	if (skin) oapiSetTexture (exmesh, 1, skin);
}


//=========================================================
// Vessel Capabilities
//=========================================================
void MyVessel::clbkSetClassCaps (FILEHANDLE cfg)
{
	// vessel caps definitions
	SetEmptyMass (EMPTY_MASS);
	SetMeshVisibilityMode (AddMesh (exmesh_tpl = oapiLoadMeshGlobal ("Pjt1")), MESHVIS_EXTERNAL);
	SetSize (105);
	SetCrossSections (_V(4829.98,4523.40,5305.31));
	SetPMI (_V(672.40,616.49,890.80));
	
	SetDockParams (_V(0,0,37.584), _V(0,0,1), _V(0,1,0));
	SetTouchdownPoints (PB_TDP[0], PB_TDP[1], PB_TDP[2]);
}

//=========================================================
// Vessel Load and Save Parameters
//=========================================================
void MyVessel::clbkLoadStateEx (FILEHANDLE scn, void *vs)
{
	char *line; while (oapiReadScenario_nextline (scn, line))
	{
		if (!strnicmp (line, "SKIN", 4))
		{
			sscanf (line+4, "%s", skinpath);
			char fname[256];
			strcpy (fname, "Pjt1\\Skins\\");
			strcat (fname, skinpath);
			int n = strlen(fname); fname[n++] = '\\';
			strcpy (fname+n, "Cabina.dds");  skin = oapiLoadTexture (fname);
		}
		else
		{
			ParseScenarioLineEx (line, vs);
		}
	}
}

void MyVessel::clbkSaveState (FILEHANDLE scn)
{

	VESSEL3::clbkSaveState (scn);
	
	
	if (skinpath[0])
		oapiWriteScenario_string (scn, "SKIN", skinpath);
}

// --------------------------------------------------------------
// Create DG visual
// --------------------------------------------------------------
void MyVessel::clbkVisualCreated (VISHANDLE vis, int refcount)
{
	visual = vis;
	exmesh = GetDevMesh (vis, 0);
	ApplySkin();
}

// --------------------------------------------------------------
// Destroy DG visual
// --------------------------------------------------------------
void MyVessel::clbkVisualDestroyed (VISHANDLE vis, int refcount)
{
	visual = NULL;
	exmesh = NULL;
}


//=========================================================
// Animation Template
//=========================================================
void MyVessel::ActivateInnerAirlock (DoorStatus action)
{
	bool close = (action == DOOR_CLOSED || action == DOOR_CLOSING);
	ilock_status = action;
	if (action <= DOOR_OPEN) {
		ilock_proc = (action == DOOR_CLOSED ? 0.0 : 1.0);
		SetAnimation (anim_ilock, ilock_proc);
	}
}

void MyVessel::RevertInnerAirlock ()
{
	ActivateInnerAirlock (ilock_status == DOOR_CLOSED || ilock_status == DOOR_CLOSING ?
		                  DOOR_OPENING : DOOR_CLOSING);
}

// --------------------------------------------------------------
// Finalise vessel creation
// --------------------------------------------------------------
void MyVessel::clbkPostCreation ()
{

	// update animation states
	SetAnimation (anim_ilock, ilock_proc);

}

// --------------------------------------------------------------
// Frame update
// --------------------------------------------------------------
void MyVessel::clbkPostStep (double simt, double simdt, double mjd)
{
	int i;
	// animate inner airlock
	if (ilock_status >= DOOR_CLOSING) {
		double da = simdt * AIRLOCK_OPERATING_SPEED;
		if (ilock_status == DOOR_CLOSING) {
			if (ilock_proc > 0.0)
				ilock_proc = max (0.0, ilock_proc-da);
			else {
				ilock_status = DOOR_CLOSED;
				//oapiTriggerPanelRedrawArea (1, AID_AIRLOCKINDICATOR);
			}
		} else { // door opening
			if (ilock_proc < 1.0)
				ilock_proc = min (1.0, ilock_proc+da);
			else {
				ilock_status = DOOR_OPEN;
				//oapiTriggerPanelRedrawArea (1, AID_AIRLOCKINDICATOR);
			}
		}
		SetAnimation (anim_ilock, ilock_proc);
	}
}

// --------------------------------------------------------------
// Process buffered key events
// --------------------------------------------------------------
int MyVessel::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{
	if (!down) return 0; // only process keydown events
	if (Playback()) return 0; // don't allow manual user input during a playback

	switch (key) {
	case OAPI_KEY_O:  // "operate outer airlock"
		RevertInnerAirlock ();
		return 1;
	}
	return 0;
}


//=========================================================
// Load and Delete Module Stuff
//=========================================================
DLLCLBK void InitModule (HINSTANCE hModule)
{
	g_hDLL = hModule;
	// perform global module initialisation here
}
DLLCLBK void ExitModule (HINSTANCE hModule)
{
	// perform module cleanup here
}

//=========================================================
// Load and Delete Vessel Stuff
//=========================================================
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new MyVessel (hvessel, flightmodel);
}
DLLCLBK void ovcExit (VESSEL *vessel)
{
	if (vessel)
		delete (MyVessel*)vessel;
}

File h.
Code:
#pragma once
#include "Orbitersdk.h"

const double EMPTY_MASS = 120000;  // standard configuration
const VECTOR3 PB_TDP[3] = {{0,-48.6,20},{-20,-48.6,-20},{20,-48.6,-20}}; // touchdown points [m]

const double AIRLOCK_OPERATING_SPEED = 0.1;
// Opening/closing speed of outer airlock (1/sec)
// => cycle = 10 sec


class MyVessel : public VESSEL3 {

public:
	MyVessel (OBJHANDLE hObj, int fmodel);
	~MyVessel ();
	
	void DefineAnimations();
	void clbkSetClassCaps (FILEHANDLE cfg);
	void clbkLoadStateEx (FILEHANDLE scn, void *vs);
	void clbkSaveState (FILEHANDLE scn);
	void Timestep (double simt);
	void clbkVisualCreated (VISHANDLE vis, int refcount);
	void clbkVisualDestroyed (VISHANDLE vis, int refcount);
	void clbkPostCreation ();
	void clbkPostStep (double simt, double simdt, double mjd);
	int  clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);

	enum DoorStatus { DOOR_CLOSED, DOOR_OPEN, DOOR_CLOSING, DOOR_OPENING }
	    ilock_status;
	void ActivateInnerAirlock (DoorStatus action);
	void RevertInnerAirlock ();
	double ilock_proc;     // logical status
	UINT anim_ilock;        // handle for inner airlock animation

	MESHHANDLE exmesh_tpl;          // vessel mesh: global template
	DEVMESHHANDLE exmesh;           // vessel mesh: instance

private:
	void ApplySkin();                            // apply custom skin
	VISHANDLE visual;                            // handle to DG visual representation
	char skinpath[32];                           // skin directory, if applicable
	SURFHANDLE skin;                          // custom skin texture, if applicable
};

Thanks:)
 
Last edited:

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Read about the standard math function "fmod". ;)
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
I understood little, but I think should be modified "ActivateInnerAirlock", but how?
"RevertInnerAirlock" method can be simplified to only negate a "play animation" flag (e.g. modified `ilock_status` to be only 2-state enum or a simple bool), and "clbkPostStep" should be modified to only check that flag and not reset it after the full cycle.

Additionally, when it's implemented, "clbkSaveState" and "clbkLoadStateEx" should load/save some "is animating" flag and the current position in the animation cycle.

But first I'd rename variables and change enums to reflect what is being done (it wouldn't be "door opening" or "door closing" continuously, would it?).
 

Dany

Addon-Dev F.O.I.
Joined
Apr 7, 2011
Messages
18
Reaction score
0
Points
0
Sorry but I could not do much. I'm not a programmer and "maybe" you were a bit too simple responses.
But first I'd rename variables and change enums to reflect what is being done (it wouldn't be "door opening" or "door closing" continuously, would it?).
Indeed should turn only in opening and at closing to stop.

But you could give an example of "ActivateInnerAirlock" in the loop, if it is must be done here.
I should add:

Code:
for ( ; ; ){.............}return 0;     //Infinite loop

But nothing, I put it anywhere and in different ways, but Can not get the animation in loop.

I would be fine a "sample" If you know of one or perhaps some useful links.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
I should add:

Code:
for ( ; ; ){.............}return 0;     //Infinite loop
That's actually what you shouldn't ever add to a vessel, unless you want to lock up Orbiter (i.e. make the single time step infinite) until user will kill its process. :p



As I understand, you want to animate/rotate something (not airlock's door) continuously and in one direction when you press a key, and stop it after you press the key again (no reverse of the direction after 3rd key press).

My proposed preliminary modifications (untested, only done in this post; stricken red - removed; green - added):
File Cpp.
Code:
#define ORBITER_MODULE
#include "MyVessel.h"

HINSTANCE g_hDLL;


// --------------------------------------------------------------
// Constructor
// --------------------------------------------------------------
MyVessel::MyVessel (OBJHANDLE hObj, int fmodel)
: VESSEL3 (hObj, fmodel)
{
[color=red][s]	ilock_status      = DOOR_CLOSED;[/s][/color]
[color=green]	shouldAnimateTheThing = false;[/color]
	ilock_proc        = 0.0;
	visual            = NULL;
	exmesh            = NULL;

	skinpath[0] = '\0';
    skin        = NULL;

	DefineAnimations();
}

// --------------------------------------------------------------
// Destructor
// --------------------------------------------------------------
MyVessel::~MyVessel ()
{
	if (skin) oapiReleaseTexture (skin);

}



//=========================================================
// Vessel Animations
//=========================================================
void MyVessel::DefineAnimations()
{
	int i;
	// ***** Inner airlock animation *****
	static UINT ILockGrp[23] = {8,9,11,12,13,14,17,18,25,26,29,30,33,34,35,36,43,84,85,87,88,89,90};
	static MGROUP_ROTATE ILock (0, ILockGrp, 23,
		_V(0, 0, 0), _V(0, 0, 1), (float)(-360*RAD));
	
	anim_ilock = CreateAnimation (0);
	AddAnimationComponent (anim_ilock, 0, 1, &ILock);
}

// --------------------------------------------------------------
// Apply custom skin to the current mesh instance
// --------------------------------------------------------------
void MyVessel::ApplySkin ()
{
	if (!exmesh) return;
	if (skin) oapiSetTexture (exmesh, 1, skin);
}


//=========================================================
// Vessel Capabilities
//=========================================================
void MyVessel::clbkSetClassCaps (FILEHANDLE cfg)
{
	// vessel caps definitions
	SetEmptyMass (EMPTY_MASS);
	SetMeshVisibilityMode (AddMesh (exmesh_tpl = oapiLoadMeshGlobal ("Pjt1")), MESHVIS_EXTERNAL);
	SetSize (105);
	SetCrossSections (_V(4829.98,4523.40,5305.31));
	SetPMI (_V(672.40,616.49,890.80));
	
	SetDockParams (_V(0,0,37.584), _V(0,0,1), _V(0,1,0));
	SetTouchdownPoints (PB_TDP[0], PB_TDP[1], PB_TDP[2]);
}

//=========================================================
// Vessel Load and Save Parameters
//=========================================================
void MyVessel::clbkLoadStateEx (FILEHANDLE scn, void *vs)
{
	char *line; while (oapiReadScenario_nextline (scn, line))
	{
		if (!strnicmp (line, "SKIN", 4))
		{
			sscanf (line+4, "%s", skinpath);
			char fname[256];
			strcpy (fname, "Pjt1\\Skins\\");
			strcat (fname, skinpath);
			int n = strlen(fname); fname[n++] = '\\';
			strcpy (fname+n, "Cabina.dds");  skin = oapiLoadTexture (fname);
		}
[color=green]		else if (!strnicmp (line, "ANIMATED_THING", 14)) {
			int intToBoolTemp; // MSVC's sscanf doesn't have a format modifier to read a 8-bit int value (other than literally the character itself)
			sscanf (line + 14, "%i %lf", &intToBoolTemp, &ilock_proc);
			shouldAnimateTheThing = intToBoolTemp != 0;
		}[/color]
		else
		{
			ParseScenarioLineEx (line, vs);
		}
	}
}

void MyVessel::clbkSaveState (FILEHANDLE scn)
{

	VESSEL3::clbkSaveState (scn);
	
	
	if (skinpath[0])
		oapiWriteScenario_string (scn, "SKIN", skinpath);
[color=green]	char buf [256];
	sprintf (buf, "%i %lf", (int)shouldAnimateTheThing, ilock_proc);
	oapiWriteScenario_string (scn, "ANIMATED_THING", buf);[/color]
}

// --------------------------------------------------------------
// Create DG visual
// --------------------------------------------------------------
void MyVessel::clbkVisualCreated (VISHANDLE vis, int refcount)
{
	visual = vis;
	exmesh = GetDevMesh (vis, 0);
	ApplySkin();
}

// --------------------------------------------------------------
// Destroy DG visual
// --------------------------------------------------------------
void MyVessel::clbkVisualDestroyed (VISHANDLE vis, int refcount)
{
	visual = NULL;
	exmesh = NULL;
}


//=========================================================
// Animation Template
//=========================================================
[color=red][s]void MyVessel::ActivateInnerAirlock (DoorStatus action)
{
	bool close = (action == DOOR_CLOSED || action == DOOR_CLOSING);
	ilock_status = action;
	if (action <= DOOR_OPEN) {
		ilock_proc = (action == DOOR_CLOSED ? 0.0 : 1.0);
		SetAnimation (anim_ilock, ilock_proc);
	}
}

void MyVessel::RevertInnerAirlock ()
{
	ActivateInnerAirlock (ilock_status == DOOR_CLOSED || ilock_status == DOOR_CLOSING ?
		                  DOOR_OPENING : DOOR_CLOSING);
}[/s][/color]

// --------------------------------------------------------------
// Finalise vessel creation
// --------------------------------------------------------------
void MyVessel::clbkPostCreation ()
{

	// update animation states
	SetAnimation (anim_ilock, ilock_proc);

}

// --------------------------------------------------------------
// Frame update
// --------------------------------------------------------------
void MyVessel::clbkPostStep (double simt, double simdt, double mjd)
{
	int i;
[color=green]	// animate the thing you want to animate :P
	if (shouldAnimateTheThing) {[/color]
[color=red][s]	// animate inner airlock
	if (ilock_status >= DOOR_CLOSING) {[/s][/color]
		double da = simdt * AIRLOCK_OPERATING_SPEED;
[color=red][s]		if (ilock_status == DOOR_CLOSING) {
			if (ilock_proc > 0.0)
				ilock_proc = max (0.0, ilock_proc-da);
			else {
				ilock_status = DOOR_CLOSED;
				//oapiTriggerPanelRedrawArea (1, AID_AIRLOCKINDICATOR);
			}
		} else { // door opening
			if (ilock_proc < 1.0)
				ilock_proc = min (1.0, ilock_proc+da);
			else {
				ilock_status = DOOR_OPEN;
				//oapiTriggerPanelRedrawArea (1, AID_AIRLOCKINDICATOR);
			}
		}[/s][/color]
[color=green]		ilock_proc = fmod (ilock_proc + da, 1.0); // it shouldn't really be called ilock_proc / ilock_anim if you animate something different than airlock[/color]
		SetAnimation (anim_ilock, ilock_proc);
	}
}

// --------------------------------------------------------------
// Process buffered key events
// --------------------------------------------------------------
int MyVessel::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{
	if (!down) return 0; // only process keydown events
	if (Playback()) return 0; // don't allow manual user input during a playback

	switch (key) {
	case OAPI_KEY_O:  // "operate outer airlock"
[color=red][s]		RevertInnerAirlock ();[/s][/color]
[color=green]		shouldAnimateTheThing = !shouldAnimateTheThing;[/color]
		return 1;
	}
	return 0;
}


//=========================================================
// Load and Delete Module Stuff
//=========================================================
DLLCLBK void InitModule (HINSTANCE hModule)
{
	g_hDLL = hModule;
	// perform global module initialisation here
}
DLLCLBK void ExitModule (HINSTANCE hModule)
{
	// perform module cleanup here
}

//=========================================================
// Load and Delete Vessel Stuff
//=========================================================
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new MyVessel (hvessel, flightmodel);
}
DLLCLBK void ovcExit (VESSEL *vessel)
{
	if (vessel)
		delete (MyVessel*)vessel;
}

File h.
Code:
#pragma once
#include "Orbitersdk.h"

const double EMPTY_MASS = 120000;  // standard configuration
const VECTOR3 PB_TDP[3] = {{0,-48.6,20},{-20,-48.6,-20},{20,-48.6,-20}}; // touchdown points [m]

const double AIRLOCK_OPERATING_SPEED = 0.1;
// Opening/closing speed of outer airlock (1/sec)
// => cycle = 10 sec


class MyVessel : public VESSEL3 {

public:
	MyVessel (OBJHANDLE hObj, int fmodel);
	~MyVessel ();
	
	void DefineAnimations();
	void clbkSetClassCaps (FILEHANDLE cfg);
	void clbkLoadStateEx (FILEHANDLE scn, void *vs);
	void clbkSaveState (FILEHANDLE scn);
	void Timestep (double simt);
	void clbkVisualCreated (VISHANDLE vis, int refcount);
	void clbkVisualDestroyed (VISHANDLE vis, int refcount);
	void clbkPostCreation ();
	void clbkPostStep (double simt, double simdt, double mjd);
	int  clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);

[color=red][s]	enum DoorStatus { DOOR_CLOSED, DOOR_OPEN, DOOR_CLOSING, DOOR_OPENING }
	    ilock_status;[/s][/color]
[color=green]	bool shouldAnimateTheThing;[/color]
[color=red][s]	void ActivateInnerAirlock (DoorStatus action);
	void RevertInnerAirlock ();[/s][/color]
	double ilock_proc;     // logical status
	UINT anim_ilock;        // handle for inner airlock animation

	MESHHANDLE exmesh_tpl;          // vessel mesh: global template
	DEVMESHHANDLE exmesh;           // vessel mesh: instance

private:
	void ApplySkin();                            // apply custom skin
	VISHANDLE visual;                            // handle to DG visual representation
	char skinpath[32];                           // skin directory, if applicable
	SURFHANDLE skin;                          // custom skin texture, if applicable
};
You should of course remove variables and methods you will no longer use or rename them accordingly if you use them for something else.
 

Dany

Addon-Dev F.O.I.
Joined
Apr 7, 2011
Messages
18
Reaction score
0
Points
0
Thank you, now I'm a try.:thumbup:

---------- Post added at 03:35 PM ---------- Previous post was at 03:10 PM ----------

Great Orb, you're a legend.
It works perfectly and as I wanted, thank you.:cheers:

That's actually what you shouldn't ever add to a vessel, unless you want to lock up Orbiter (i.e. make the single time step infinite) until user will kill its process. :p

Indeed, it happened to restart the computer, orbiter did not want to close.

There is a method to their names? Okay, "anim_GraArt."
:tiphat:
 
Top