A discussion of customized prop discs for authors can be found here.

#include <string.h>
#include <math.h>
#include "XPLMDataAccess.h"
#include "XPLMProcessing.h"

static XPLMDataRef		prop_rotation_speed_rad_sec = NULL;
static XPLMDataRef		prop_rotation_angle_deg = NULL;
static XPLMDataRef		side_angle = NULL;
static XPLMDataRef		prop_is_disc = NULL;
static XPLMDataRef		disc_s = NULL;
static XPLMDataRef		disc_t = NULL;
static XPLMDataRef		side_s = NULL;
static XPLMDataRef		side_t = NULL;
static XPLMDataRef		sim_speed = NULL;
static XPLMDataRef		frame_rate_period = NULL;

// Interp - rescales a floating point variable, clamping to the outer limits.  Handy
// for mapping a range of physics behavior to something in the graphics.
static float interp(float in1, float out1, float in2, float out2, float x)
{
	if(x < in1) return out1;
	if(x > in2) return out2;
	return out1 + (out2 - out1) * (x - in1) / (in2 - in1);
}

// Two util funcs to write the first two slots of array datarefs...we do this a lot, 
// so this saves some typing.
static void set_2f(XPLMDataRef r, float v1, float v2)
{
	float v[2] = { v1, v2 };
	XPLMSetDatavf(r,v,0,2);
}

static void set_2i(XPLMDataRef r, int i1, int i2)
{
	int i[2] = { i1, i2 };
	XPLMSetDatavi(r,i,0,2);
}

static float deferred_init(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	// These get set once when we take over the airplane...these are custom prop disc settings that
	// we won't change per frame.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/override"), 1, 1);

	// Our prop disc has 4 slots across and 2 down.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_s_dim"), 4, 4);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_t_dim"), 2, 2);
	
	// Alpha settings for the prop disc.
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_front"), 1.0, 1.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_side"), 0.1, 0.1);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_alpha_inside"), 0.8, 0.8);
	
	// Side is a 2-blade prop 15 cm wide.  We have 32x2 slots for side discs.
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_width") , 0.15, 0.15);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_number_of_blades"), 2, 2);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_s_dim"), 32, 32);
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_t_dim"), 2, 2);
	// Alpha setting for side disc is separate
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_front"), 0.0, 0.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_side"), 1.0, 1.0);
	set_2f(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_alpha_inside"), 0.8, 0.8);
	// Do not use auto-billboarding.  We will spin the side disc ourselves.
	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_is_billboard"), 0, 0);
	
	return 0;
}

static float prop_per_frame(
                                   float                inElapsedSinceLastCall,    
                                   float                inElapsedTimeSinceLastFlightLoop,    
                                   int                  inCounter,    
                                   void *               inRefcon)
{
	float prop_speed_now[2];
	float prop_angle_now[2];
	float side_angle_now[2];

	// First we need to know how fast the sim is really running - a function
	// of the sim speed and framerate period.  We also need to know how fast our
	// disc is going.  Btw s in seconds per frame.
	float s = XPLMGetDatai(sim_speed);
	s *= XPLMGetDataf(frame_rate_period);
	XPLMGetDatavf(prop_rotation_speed_rad_sec,prop_speed_now,0,2);
	
	// And - where is our disc right now.
	XPLMGetDatavf(side_angle,side_angle_now,0,2);
	XPLMGetDatavf(prop_rotation_angle_deg,prop_angle_now,0,2);

	// "Spin" the disc just a bit and write it bck.
	prop_angle_now[0] += prop_speed_now[0] * s * 60.0;
	prop_angle_now[1] += prop_speed_now[1] * s * 60.0;
	side_angle_now[0] += prop_speed_now[0] * s * 60.0;
	side_angle_now[1] += prop_speed_now[1] * s * 60.0;
	
	XPLMSetDatavf(side_angle,side_angle_now, 0, 2);
	XPLMSetDatavf(prop_rotation_angle_deg,prop_angle_now, 0, 2);

	// Individual blades or a disc?  We switch at greater than 18 rads/sec spinning.
	set_2i(prop_is_disc, prop_speed_now[0] > 18.0, prop_speed_now[1] > 18.0);

	// We pick our texture slots by interping the prop speed.  So as the prop speeds up, we
	// pick different slots.
	set_2f(disc_s,interp(15,0,100,2,prop_speed_now[0]),interp(15,0,100,2,prop_speed_now[1]));
	set_2i(disc_t,0,1);

	set_2f(side_s,interp(15,26,100,24,prop_speed_now[0]),interp(15,24,100,26,prop_speed_now[1]));
	set_2i(side_t,0,1);

	return -1.0;	
}


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	strcpy(outName, "Custom Prop Disc Example");
	strcpy(outSig, "xplanesdk.examples.custom_prop_disc");
	strcpy(outDesc, "A plugin that demonstrates custom prop disc patterns.");

	XPLMRegisterFlightLoopCallback(deferred_init, -1.0, NULL);
	XPLMRegisterFlightLoopCallback(prop_per_frame, -2.0, NULL);

	prop_rotation_speed_rad_sec = XPLMFindDataRef("sim/flightmodel2/engines/prop_rotation_speed_rad_sec");
	prop_rotation_angle_deg = XPLMFindDataRef("sim/flightmodel2/engines/prop_rotation_angle_deg");
	side_angle = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_angle");
	prop_is_disc = XPLMFindDataRef("sim/flightmodel2/engines/prop_is_disc");
	disc_s = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_s");
	disc_t = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/disc_t");
	side_s = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_s");
	side_t = XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/side_t");
	sim_speed = XPLMFindDataRef("sim/time/sim_speed");
	frame_rate_period = XPLMFindDataRef("sim/operation/misc/frame_rate_period");

	
	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	XPLMUnregisterFlightLoopCallback(deferred_init,NULL);
	XPLMUnregisterFlightLoopCallback(prop_per_frame,NULL);

	set_2i(XPLMFindDataRef("sim/flightmodel2/engines/prop_disc/override"), 0, 0);


}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginReceiveMessage(
					XPLMPluginID	inFromWho,
					int				inMessage,
					void *			inParam)
{
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not report bugs in the blog comments.
Only bugs reported via the X-Plane Bug Reporter are tracked.